Main Content

MISRA C++:2023 Rule 21.6.3

Advanced memory management shall not be used

Since R2024b

Description

Rule Definition

Advanced memory management shall not be used

Rationale

Using advanced memory management relies on properly handling complex issues such as object lifetimes and use of std::launder. These complexities can result in difficult issues that are hard to identify and result in undefined behavior.

Examples of advanced memory management functions include:

  • All overloads of operator new and operator delete except for these overloads and their array counterparts:

    • void * operator new (std::size_t count);

    • void * operator new (std::size_t count, const std::nothrow_t & tag);

    • void operator delete (void * ptr) noexcept;

    • void operator delete (void * ptr, std::size_t sz) noexcept;

    • void operator delete (void * ptr, const std::nothrow_t & tag) noexcept;

  • Use of std::launder

  • Functions provided by the header file <memory> including:

    • destroy(), destroy_at(), and destroy_n()

    • uninitialized_copy() and uninitialized_copy_n()

    • uninitialized_move() and uninitialized_move_n()

    • uninitialized_fill() and uninitialized_fill_n()

    • uninitialized_default_construct() and uninitialized_default_construct_n()

    • uninitialized_value_construct() and uninitialized_value_construct_n()

    For a full list of advanced memory management functions and exceptions, see the MISRA™ C++:2023 documentation.

Uses of advanced memory management include:

  • Calling an advanced memory management function directly or by using a new expression or a delete expression

  • Taking the address of an advanced memory management function

  • Explicitly calling a destructor

  • Declaring an operator new or operator delete function

Polyspace Implementation

Polyspace® reports violations on:

  • Declarations or uses of any advanced memory management function

  • Overloads of operator new and operator delete (not including exceptions described in the Rationale section)

  • Explicitly calling a destructor or explicitly declaring an operator new or operator delete function

Troubleshooting

If you expect a rule violation but Polyspace does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

#include <iostream>
#include <memory>
#include <vector>
#include <string>

int main() {
    std::vector<std::string> source = {"Hello", "World", "C++", "Memory"};
    void* rawMemory = operator new[](source.size() * sizeof(std::string));  // Compliant

    std::string* dest = static_cast<std::string*>(rawMemory);

    try {
        std::uninitialized_copy(source.begin(), source.end(), dest);        // Noncompliant

        for (size_t i = 0; i < source.size(); ++i) {
            std::cout << dest[i] << std::endl;
        }
        std::destroy(dest, dest + source.size());                           // Noncompliant
    } catch (...) {
        operator delete[](rawMemory);
        throw;  
    }

    operator delete[](rawMemory);

    return 0;
}

This example uses std::uninitialized_copy() to create a string object inside rawMemory by copying from the source vector. Use of std::uninitialized_copy() is noncompliant.

While the operator new[]() function is compliant for this rule, it is still a nonautomatic form of memory management and violates MISRA C++:2023 Rule 21.6.2.

#include <new>
#include <iostream>

struct X { int m; };

int main() {
    unsigned char buf[sizeof(X)];
    X* p = new (buf) X{2023};                        // Noncompliant
    p->~X();                                         // Noncompliant
    X* q = new (buf) X{42};                          // Noncompliant
    std::cout << std::launder(q)->m << std::endl;    // Noncompliant
}

In this example, two overloads of operator new occur, which is advanced memory management. The code also explicitly calls a destructor in p->~X();.

Check Information

Group: Language support library
Category: Required

Version History

Introduced in R2024b