operator delete, operator delete[]

From cppreference.com
< cpp‎ | memory‎ | new
Utilities library
General utilities
Relational operators (deprecated in C++20)
Integer comparison functions
(C++20)(C++20)(C++20)
(C++20)
Swap and type operations
(C++20)
(C++14)
(C++11)
(C++23)
(C++11)
(C++23)
(C++11)
(C++17)
Common vocabulary types
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++11)
(C++17)
(C++17)
(C++23)



Memory management library
(exposition only*)
Uninitialized memory algorithms
(C++17)
(C++17)
(C++17)
(C++20)
Constrained uninitialized
memory algorithms
(C++20)
C Library

Allocators
(C++11)
(C++11)
Memory resources
Garbage collection support
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
Uninitialized storage
(until C++20*)
(until C++20*)
(until C++20*)
Explicit lifetime management
Defined in header <new>
replaceable usual deallocation functions
(1)
void operator delete  ( void * ptr ) throw ( ) ;
(until C++11)
void operator delete  ( void * ptr ) noexcept ;
(since C++11)
(2)
void operator delete[ ] ( void * ptr ) throw ( ) ;
(until C++11)
void operator delete[ ] ( void * ptr ) noexcept ;
(since C++11)
void operator delete  ( void * ptr, std::align_val_t al ) noexcept ;
(3) (since C++17)
void operator delete[ ] ( void * ptr, std::align_val_t al ) noexcept ;
(4) (since C++17)
void operator delete  ( void * ptr, std::size_t sz ) noexcept ;
(5) (since C++14)
void operator delete[ ] ( void * ptr, std::size_t sz ) noexcept ;
(6) (since C++14)
void operator delete  ( void * ptr, std::size_t sz,
std::align_val_t al ) noexcept ;
(7) (since C++17)
void operator delete[ ] ( void * ptr, std::size_t sz,
std::align_val_t al ) noexcept ;
(8) (since C++17)
replaceable placement deallocation functions
(9)
void operator delete  ( void * ptr, const std::nothrow_t & tag ) throw ( ) ;
(until C++11)
void operator delete  ( void * ptr, const std::nothrow_t & tag ) noexcept ;
(since C++11)
(10)
void operator delete[ ] ( void * ptr, const std::nothrow_t & tag ) throw ( ) ;
(until C++11)
void operator delete[ ] ( void * ptr, const std::nothrow_t & tag ) noexcept ;
(since C++11)
void operator delete  ( void * ptr, std::align_val_t al,
const std::nothrow_t & tag ) noexcept ;
(11) (since C++17)
void operator delete[ ] ( void * ptr, std::align_val_t al,
const std::nothrow_t & tag ) noexcept ;
(12) (since C++17)
non-allocating placement deallocation functions
(13)
void operator delete  ( void * ptr, void * place ) throw ( ) ;
(until C++11)
void operator delete  ( void * ptr, void * place ) noexcept ;
(since C++11)
(14)
void operator delete[ ] ( void * ptr, void * place ) throw ( ) ;
(until C++11)
void operator delete[ ] ( void * ptr, void * place ) noexcept ;
(since C++11)
user-defined placement deallocation functions
void operator delete  ( void* ptr, args... );
(15)
void operator delete[ ] ( void * ptr, args... ) ;
(16)
class-specific usual deallocation functions
void T:: operator delete  ( void * ptr ) ;
(17)
void T:: operator delete[ ] ( void * ptr ) ;
(18)
void T:: operator delete  ( void * ptr, std::align_val_t al ) ;
(19) (since C++17)
void T:: operator delete[ ] ( void * ptr, std::align_val_t al ) ;
(20) (since C++17)
void T:: operator delete  ( void * ptr, std::size_t sz ) ;
(21)
void T:: operator delete[ ] ( void * ptr, std::size_t sz ) ;
(22)
void T:: operator delete  ( void * ptr, std::size_t sz, std::align_val_t al ) ;
(23) (since C++17)
void T:: operator delete[ ] ( void * ptr, std::size_t sz, std::align_val_t al ) ;
(24) (since C++17)
class-specific placement deallocation functions
void T:: operator delete  ( void * ptr, args... ) ;
(25)
void T:: operator delete[ ] ( void * ptr, args... ) ;
(26)
class-specific usual destroying deallocation functions
void T:: operator delete( T* ptr, std::destroying_delete_t ) ;
(27) (since C++20)
void T:: operator delete( T* ptr, std::destroying_delete_t,
std::align_val_t al ) ;
(28) (since C++20)
void T:: operator delete( T* ptr, std::destroying_delete_t, std::size_t sz ) ;
(29) (since C++20)
void T:: operator delete( T* ptr, std::destroying_delete_t,
std::size_t sz, std::align_val_t al ) ;
(30) (since C++20)

Deallocates storage previously allocated by a matching operator new. These deallocation functions are called by delete-expressions and by new-expressions

1) Called by delete-expressions to deallocate storage previously allocated for a single object.
The behavior of the standard library implementation of this function is undefined unless ptr is a null pointer or is a pointer previously obtained from the standard library implementation of operator new ( std::size_t ) or operator new ( std::size_t, std::nothrow_t )
2) Called by delete[]-expressions to deallocate storage previously allocated for an array of objects.
The behavior of the standard library implementation of this function is undefined unless ptr is a null pointer or is a pointer previously obtained from the standard library implementation of operator new [ ] ( std::size_t ) or operator new [ ] ( std::size_t, std::nothrow_t )
3,4) Same as (1,2), except called if the alignment requirement exceeds __STDCPP_DEFAULT_NEW_ALIGNMENT__
5,6) Called instead of (1,2) if a user-defined replacement is provided, except that it's unspecified whether (1,2) or (5,6)
The standard library implementations are identical to (1,2).
7,8) Same as (5,6), except called if the alignment requirement exceeds __STDCPP_DEFAULT_NEW_ALIGNMENT__
9) Called by the non-throwing single-object new-expressions if a constructor of the object throws an exception.
The standard library implementation behaves the same as (1).
10) Called by the non-throwing array new[]-expressions
The standard library implementation behaves the same as (2).
11,12) Same as (9,10), except called if the alignment requirement exceeds __STDCPP_DEFAULT_NEW_ALIGNMENT__
13) Called by the standard single-object placement new expression if the object's constructor throws an exception.
The standard library implementation of this function does nothing.
14) Called by the standard array form of the placement new[]
The standard library implementation of this function does nothing.
15) If defined, called by the custom single-object placement new
If a class-specific version (25) is defined, it is called in preference to (9).
If neither (25) nor (15) is provided by the user, no deallocation function is called.
16) If defined, called by the custom array form of placement new[]
If a class-specific version (26) is defined, it is called in preference to (10).
If neither (26) nor (16) is provided by the user, no deallocation function is called.
17) If defined, called by the usual single-object delete-expressions if deallocating an object of type T.
18) If defined, called by the usual array delete[]-expressions if deallocating an array of objects of type T.
19,20) If defined, called in preference to (17,18) if the alignment requirement exceeds __STDCPP_DEFAULT_NEW_ALIGNMENT__
21) If defined, and if (17) is not defined, called by the usual single-object delete-expressions if deallocating an object of type T
22) If defined, and if (18) is not defined, called by the usual array delete[]-expressions if deallocating an array of objects of type T
23,24) If defined, and if (19,20) are not defined, called in preference to allocator-unaware members if the alignment requirement exceeds __STDCPP_DEFAULT_NEW_ALIGNMENT__
25) If defined, called by the custom single-object placement new
If this function is not provided, and a matching (15) is not provided either, no deallocation function is called.
26) If defined, called by the custom array form of placement new[]
If this function is not provided, and a matching (16) is not provided either, no deallocation function is called.
27-30) If defined, delete-expressions does not execute the destructor for *p before placing a call to operator delete. Instead, direct invocation of the destructor such as by p->~T();

See delete-expression

(since C++17)

In all cases, if ptr

After the standard library deallocation function returns, all pointers referring to any part of the deallocated storage become invalid.

Indirection through a pointer that became invalid in this manner and passing it to a deallocation function (double-delete) is undefined behavior. Any other use is implementation-defined.

Parameters

ptr - pointer to a memory block to deallocate or a null pointer
sz - the size that was passed to the matching allocation function
place - pointer used as the placement parameter in the matching placement new
tag - overload disambiguation tag matching the tag used by non-throwing operator new
al - alignment of the object or array element that was allocated
args - arbitrary parameters matching a placement allocation function (may include std::size_t and std::align_val_t

Return value

(none)

Exceptions

All deallocation functions are noexcept(true) unless specified otherwise in the declaration.

(since C++11)

If a deallocation function terminates by throwing an exception, the behavior is undefined , even if it is declared with noexcept(false) (since C++11)

Global replacements

The replaceable deallocation functions (1-12) are implicitly declared in each translation unit even if the <new> header is not included. These functions are replaceable

The program is ill-formed, no diagnostic required if more than one replacement is provided in the program or if a replacement is declared with the inline

The standard library implementations of the nothrow versions (9,10) directly call the corresponding throwing versions (1,2). The standard library implementations of the size-aware deallocation functions (5-8) directly call the corresponding size-unaware deallocation functions (1-4). The standard library implementations of size-unaware throwing array forms (2,4) directly calls the corresponding single-object forms (1,3). Thus, replacing the throwing single object deallocation functions (1,3)

Global operators new/delete replacement:

#include <cstdio>
#include <cstdlib>
#include <new>
 
// no inline, required by [replacement.functions]/3
void* operator new(std::size_t sz)
{
    std::printf("1) new(size_t), size = %zu\n", sz);
    if (sz == 0)
        ++sz; // avoid std::malloc(0) which may return nullptr on success
 
    if (void *ptr = std::malloc(sz))
        return ptr;
 
    throw std::bad_alloc{}; // required by [new.delete.single]/3
}
 
// no inline, required by [replacement.functions]/3
void* operator new[](std::size_t sz)
{
    std::printf("2) new[](size_t), size = %zu\n", sz);
    if (sz == 0)
        ++sz; // avoid std::malloc(0) which may return nullptr on success
 
    if (void *ptr = std::malloc(sz))
        return ptr;
 
    throw std::bad_alloc{}; // required by [new.delete.single]/3
}
 
void operator delete(void* ptr) noexcept
{
    std::puts("3) delete(void*)");
    std::free(ptr);
}
 
void operator delete(void* ptr, std::size_t size) noexcept
{
    std::printf("4) delete(void*, size_t), size = %zu\n", size);
    std::free(ptr);
}
 
void operator delete[](void* ptr) noexcept
{
    std::puts("5) delete[](void* ptr)");
    std::free(ptr);
}
 
void operator delete[](void* ptr, std::size_t size) noexcept
{
    std::printf("6) delete[](void*, size_t), size = %zu\n", size);
    std::free(ptr);
}
 
int main()
{
    int* p1 = new int;
    delete p1;
 
    int* p2 = new int[10]; // guaranteed to call the replacement in C++11
    delete[] p2;
}

Possible output:

// Compiled with GCC-5 in C++17 mode to obtain the following:
1) op new(size_t), size = 4
4) op delete(void*, size_t), size = 4
2) op new[](size_t), size = 40
5) op delete[](void* ptr)

Overloads of operator delete and operator delete[] with additional user-defined parameters ("placement forms", (15,16)) may be declared at global scope as usual, and are called by the matching placement forms of new-expressions

The standard library placement forms of operator delete (13,14) cannot be replaced and can only be customized if the placement new-expression did not use the ::new syntax, by providing a class-specific placement delete (25,26) with matching signature: void T:: operator delete( void *, void * ) or void T:: operator delete[ ] ( void *, void * )

Class-specific overloads

Deallocation functions (17-24) may be defined as static member functions of a class. These deallocation functions, if provided, are called by delete-expressions when deleting objects (17,19,21) and arrays (18,20,22) of this class, unless the delete expression used the form ::delete which bypasses class-scope lookup. The keyword static

The delete expression looks for appropriate deallocation function's name starting from the class scope (array form looks in the scope of the array element class) and proceeds to the global scope if no members are found as usual. Note, that as per name lookup rules

If the static type of the object that is being deleted differs from its dynamic type (such as when deleting a polymorphic

If the single-argument overload (17,18) is not provided, but the size-aware overload taking std::size_t as the second parameter (21,22

#include <cstddef>
#include <iostream>
 
// sized class-specific deallocation functions
struct X
{
    static void operator delete(void* ptr, std::size_t sz)
    {
        std::cout << "custom delete for size " << sz << '\n';
        ::operator delete(ptr);
    }
 
    static void operator delete[](void* ptr, std::size_t sz)
    {
        std::cout << "custom delete for size " << sz << '\n';
        ::operator delete[](ptr);
    }
};
 
int main()
{
    X* p1 = new X;
    delete p1;
 
    X* p2 = new X[10];
    delete[] p2;
}

Possible output:

custom delete for size 1
custom delete for size 18

Overloads of operator delete and operator delete[] with additional user-defined parameters ("placement forms", (25,26

#include <cstddef>
#include <iostream>
#include <stdexcept>
 
struct X
{
    X() { throw std::runtime_error("X(): std::runtime_error"); }
 
    // custom placement new
    static void* operator new(std::size_t sz, bool b)
    {
        std::cout << "custom placement new called, b = " << b << '\n';
        return ::operator new(sz);
    }
 
    // custom placement delete
    static void operator delete(void* ptr, bool b)
    {
        std::cout << "custom placement delete called, b = " << b << '\n';
        ::operator delete(ptr);
    }
};
 
int main()
{
    try
    {
        [[maybe_unused]] X* p1 = new (true) X;
    }
    catch (const std::exception& ex)
    {
        std::cout << ex.what() << '\n';
    }
}

Output:

custom placement new called, b = 1
custom placement delete called, b = 1
X(): std::runtime_error

If class-level operator delete is a template function, it must have the return type of void, the first argument void * , and it must have two or more parameters. In other words, only placement forms can be templates. A template instance is never a usual deallocation function, regardless of its signature. The specialization of the template operator delete is chosen with template argument deduction

Notes

The call to the class-specific T::operator delete

If the behavior of a deallocation function does not satisfy the default constraints, the behavior is undefined.

The following functions are required to be thread-safe:

Calls to these functions that allocate or deallocate a particular unit of storage occur in a single total order, and each such deallocation call happens-before

(since C++11)
Feature-test macro Value Std Feature
__cpp_sized_deallocation 201309L (C++14) Sized deallocation
__cpp_impl_destroying_delete 201806L (C++20) Destroying operator delete (compiler support)
__cpp_lib_destroying_delete 201806L (C++20) Destroying operator delete (library support)

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 220 C++98 user-defined deallocation functions were permitted to throw throwing from a deallocation function
results in undefined behavior
CWG 1438 C++98 any use of an invalid pointer value was undefined behavior only indirection and deallocation are
LWG 206 C++98 replacing (2) did not affect the default behavior of (10) the default behavior changes accordingly
LWG 298 C++98 replacing (1) did not affect the default behavior of (9) the default behavior changes accordingly
LWG 404 C++98 replacements of the replaceable deallocation
functions could be declared inline
prohibited, no diagnostic required
LWG 2458 C++14 overloads taking ( void *, std::size_t, const
std::nothrow_t&)
removed spurious overloads

See also

[static] (C++23)
deallocates memory previously obtained from operator new
(public static member function of std::generator<Ref,V,Allocator>::promise_type)
allocation functions
(function)
(deprecated in C++17)(removed in C++20)
frees uninitialized storage
(function template)
deallocates previously allocated memory
(function)