This is a draft version of a MISRA C++ 202x rule proposed for public review.
MISRA Rule 21.6.3
Category: Required
Analysis Type: Decidable,Single Translation Unit
Amplification
All overloads of operator new
and operator delete
that are not listed below are advanced memory management
functions:
void * operator new ( std::size_t count );
void * operator new[]( std::size_t count );
void * operator new ( std::size_t count, const std::nothrow_t & tag );
void * operator new[]( std::size_t count, const std::nothrow_t & tag );
void operator delete ( void * ptr ) noexcept;
void operator delete[]( void * ptr ) noexcept;
void operator delete ( void * ptr, std::size_t sz ) noexcept;
void operator delete[]( void * ptr, std::size_t sz ) noexcept;
void operator delete ( void * ptr, const std::nothrow_t & tag ) noexcept;
void operator delete[]( void * ptr, const std::nothrow_t & tag ) noexcept;
Additionally, std::launder
and the following functions from the <memory>
header file [1] are also
advanced memory management functions:
uninitialized_default_construct uninitialized_default_construct_n destroy
uninitialized_value_construct uninitialized_value_construct_n destroy_at
uninitialized_copy uninitialized_copy_n destroy_n
uninitialized_move uninitialized_move_n
uninitialized_fill uninitialized_fill_n
Advanced memory management occurs when:
- An advanced memory management function is either called directly or through a new-expression or a delete-expression;
or
- The address of an advanced memory management function is taken; or
- A destructor is called explicitly; or
- Any
operator new
or operator delete
is user-declared.
Rationale
There are a number of complex issues, such as alignment, object lifetimes and the need to use std::launder
, that must be considered
when using advanced memory management. Failure to deal with these appropriately results in the introduction of undefined behaviour
that is hard to identify.
In addition, undefined behaviour results if a user does not provide matching versions of operator new
and operator
delete
.
These features are generally only used (requiring a deviation) for low-level programming. Ideally, they should be encapsulated to reduce the amount
of additional code review that will be required.
Example
auto f() noexcept
{
return new( std::nothrow ) int{ 42 }; // Compliant
}
struct X { int32_t a; };
int32_t g()
{
alignas( X ) std::byte mem[ sizeof( X ) ];
X * px = new( &mem ) X{ 1 }; // Non-compliant - placement new
px->~X(); // Non-compliant - explicit destructor call
new( px ) X { 2 }; // Non-compliant - placement new
return px->a ; // Undefined behaviour
}
struct A
{
void * operator new( size_t ); // Non-compliant
};
Glossary
[1] Header file
A header file is considered to be any file that is included during preprocessing (for example via the #include
directive),
regardless of its name or suffix.
Copyright The MISRA Consortium Limited © 2023