Namespaces
Variants

operator delete , operator delete[]

From cppreference.net
< cpp ‎ | memory ‎ | new
Utilities library
Memory management library
( exposition only* )
Allocators
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Memory resources
Uninitialized storage (until C++20)
( until C++20* )
( until C++20* )
( until C++20* )

Garbage collector support (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)
(C++11) (until C++23)
**Примечание:** В данном фрагменте HTML-кода отсутствует текст для перевода, требующий локализации на русский язык. Весь представленный контент состоит из: 1. HTML-тегов и атрибутов (оставлены без изменений) 2. C++ кода внутри тегов ` ` (сохранен в оригинале) 3. Числового обозначения версии "(21)" (не требует перевода) Если бы в документе присутствовали поясняющие тексты на английском языке вне код-блоков, они были бы переведены на русский с сохранением профессиональной терминологии C++. **Примечание:** В данном фрагменте HTML не содержится переводимого текста за пределами тегов ` `, `
`, ``. Весь код C++ и HTML-разметка сохранены в оригинальном виде согласно требованиям.
(Примечание: В данном фрагменте HTML отсутствует текстовое содержимое для перевода - присутствуют только HTML-теги и атрибуты, которые согласно инструкциям не подлежат переводу)
Определено в заголовке <new>
Заменяемые обычные функции деаллокации
(1)
void operator delete ( void * ptr ) throw ( ) ;
(до C++11)
void operator delete ( void * ptr ) noexcept ;
(начиная с C++11)
(2)
void operator delete [ ] ( void * ptr ) throw ( ) ;
(до C++11)
void operator delete [ ] ( void * ptr ) noexcept ;
(начиная с C++11)
void operator delete ( void * ptr, std:: align_val_t al ) noexcept ;
(3) (начиная с C++17)
void operator delete [ ] ( void * ptr, std:: align_val_t al ) noexcept ;
(4) (начиная с C++17)
void operator delete ( void * ptr, std:: size_t sz ) noexcept ;
(5) (начиная с C++14)
void operator delete [ ] ( void * ptr, std:: size_t sz ) noexcept ;
(6) (начиная с C++14)
void operator delete ( void * ptr, std:: size_t sz,
std:: align_val_t al ) noexcept ;
(7) (начиная с C++17)
void operator delete [ ] ( void * ptr, std:: size_t sz,
std:: align_val_t al ) noexcept ;
(8) (начиная с C++17)
Заменяемые функции размещающего освобождения
(9)
void operator delete ( void * ptr, const std:: nothrow_t & tag ) throw ( ) ;
(до C++11)
void operator delete ( void * ptr, const std:: nothrow_t & tag ) noexcept ;
(начиная с C++11)
(10)
void operator delete [ ] ( void * ptr, const std:: nothrow_t & tag ) throw ( ) ;
(до C++11)
void operator delete [ ] ( void * ptr, const std:: nothrow_t & tag ) noexcept ;
(начиная с C++11)
void operator delete ( void * ptr, std:: align_val_t al,
const std:: nothrow_t & tag ) noexcept ;
(11) (начиная с C++17)
void operator delete [ ] ( void * ptr, std:: align_val_t al,
const std:: nothrow_t & tag ) noexcept ;
(12) (начиная с C++17)
Функции размещающей деаллокации без выделения памяти
(13)
void operator delete ( void * ptr, void * place ) throw ( ) ;
(до C++11)
void operator delete ( void * ptr, void * place ) noexcept ;
(начиная с C++11)
(14)
void operator delete [ ] ( void * ptr, void * place ) throw ( ) ;
(до C++11)
void operator delete [ ] ( void * ptr, void * place ) noexcept ;
(начиная с C++11)
Пользовательские функции размещающего освобождения
void operator delete ( void * ptr, args... ) ;
(15)
void operator delete [ ] ( void * ptr, args... ) ;
(16)
Класс-специфичные обычные функции деаллокации
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) (начиная с C++17)
void T :: operator delete [ ] ( void * ptr, std:: align_val_t al ) ;
(20) (начиная с 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) (начиная с C++17)
void T :: operator delete [ ] ( void * ptr, std:: size_t sz, std:: align_val_t al ) ;
(24) (начиная с C++17)
Класс-специфичные функции размещающего освобождения
void T :: operator delete ( void * ptr, args... ) ;
(25)
void T :: operator delete [ ] ( void * ptr, args... ) ;
(26)
Класс-специфичные обычные деаллоцирующие функции уничтожения
void T :: operator delete ( T * ptr, std:: destroying_delete_t ) ;
(27) (начиная с C++20)
void T :: operator delete ( T * ptr, std:: destroying_delete_t ,
std:: align_val_t al ) ;
(28) (начиная с C++20)
void T :: operator delete ( T * ptr, std:: destroying_delete_t , std:: size_t sz ) ;
(29) (начиная с C++20)
void T :: operator delete ( T * ptr, std:: destroying_delete_t ,
std:: size_t sz, std:: align_val_t al ) ;
(30) (начиная с C++20)

Освобождает память, ранее выделенную соответствующим operator new или operator new[] . Эти функции освобождения памяти вызываются delete и delete [ ] выражениями , а также placement new выражениями для освобождения памяти после деструкции (или неудачного конструирования) объектов с динамической продолжительностью хранения. Они также могут быть вызваны с использованием обычного синтаксиса вызова функций.

1-12) Replaceable функции освобождения памяти. Стандартная библиотека предоставляет реализации по умолчанию для этих функций; для описания эффектов реализаций по умолчанию см. ниже .
1-8) Вызывается выражениями delete и delete [ ] . Делает недействительным любой ненулевой ptr .
9-12) Вызывается выражениями размещающего new при сбое инициализации . operator delete [ ] делает недействительным любой ненулевой ptr .
Если ptr не является нулевым указателем и выполняется одно из следующих условий, поведение не определено:
  • Для operator delete , значение ptr не представляет адрес блока памяти, выделенного предыдущим вызовом (возможно заменённого) operator new ( std:: size_t ) (для перегрузок (1,5,9) ) или operator new ( std:: size_t , std:: align_val_t ) (для перегрузок (3,7,11) ), который не был аннулирован промежуточным вызовом operator delete .
  • Для operator delete [ ] , значение ptr не представляет адрес блока памяти, выделенного предыдущим вызовом (возможно заменённого) operator new [ ] ( std:: size_t ) (для перегрузок (2,6,10) ) или operator new [ ] ( std:: size_t , std:: align_val_t ) (для перегрузок (4,8,12) ), который не был аннулирован промежуточным вызовом operator delete [ ] .
13,14) Вызывается выражениями размещения new , которые вызвали не-аллоцирующую функцию размещения , когда любая часть инициализации в выражении завершается выбрасыванием исключения. Не выполняет никаких действий.
15-30) Пользовательские функции освобождения памяти, вызываемые выражениями delete , delete [ ] и размещающим new .
27-30) Если определено, delete выражения не выполняют деструктор для * ptr перед вызовом operator delete . Вместо этого, прямое обращение к деструктору, например через ptr - > ~T ( ) ; становится ответственностью этого operator delete .

Перегрузки ( 1-8 ) неявно объявляются в каждой единице трансляции, даже если заголовочный файл <new> не включен.

См. delete expression для критериев выбора перегрузки.

Содержание

Параметры

ptr - указатель на блок памяти для освобождения или нулевой указатель
sz - размер, переданный соответствующей функции выделения памяти
place - указатель, используемый в качестве параметра размещения в соответствующем placement new
tag - тег разрешения перегрузки, соответствующий тегу, используемому в non-throwing operator new
al - выравнивание объекта или элемента массива, который был выделен
args - произвольные параметры, соответствующие функции размещающего выделения памяти (могут включать std::size_t и std::align_val_t )

Исключения

Все функции освобождения памяти являются noexcept ( true ) если не указано иное в объявлении.

(начиная с C++11)

Если функция освобождения завершается выбрасыванием исключения, поведение не определено , даже если она объявлена с noexcept ( false ) (начиная с C++11) .

Глобальные замены

Перегрузки ( 1-12 ) являются заменяемыми . Эффекты версий по умолчанию следующие:

1) Если ptr является нулевым, ничего не делает. В противном случае освобождает память, выделенную предыдущим вызовом operator new .
2) Вызывает operator delete ( ptr ) как если бы перегрузка (1) могла вернуть память, выделенную предыдущим вызовом operator new [ ] .
3) То же, что и (1) .
4) Вызывает operator delete ( ptr, al ) как если бы перегрузка (3) могла освободить память, выделенную предыдущим вызовом operator new [ ] .
5) Вызывает operator delete ( ptr ) .
6) Вызывает operator delete [ ] ( ptr ) .
7) Вызывает operator delete ( ptr, al ) .
8) Вызывает operator delete [ ] ( ptr, al ) .
9) Вызывает operator delete ( ptr ) .
10) Вызывает operator delete [ ] ( ptr ) .
11) Вызывает operator delete ( ptr, al ) .
12) Вызывает operator delete [ ] ( ptr, al ) .

Глобальная замена operator new / delete :

#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;
}

Возможный вывод:

// 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)

Перегрузки operator delete и operator delete [ ] с дополнительными пользовательскими параметрами ("placement forms", ( 15,16 ) ) могут быть объявлены в глобальной области видимости как обычно и вызываются соответствующими placement формами выражений new , если конструктор выделяемого объекта выбрасывает исключение.

Стандартные библиотечные формы размещающего operator delete и operator delete [ ] ( 13,14 ) не могут быть заменены и могут быть кастомизированы только если выражение размещающего new не использовало синтаксис :: new , путем предоставления класс-специфичного размещающего delete ( 25,26 ) с соответствующей сигнатурой: void T :: operator delete ( void * , void * ) или void T :: operator delete [ ] ( void * , void * ) .

Перегрузки, специфичные для класса

Функции освобождения памяти ( 17-24 ) могут быть определены как статические функции-члены класса. Эти функции освобождения, если они предоставлены, вызываются выражениями delete при удалении объектов ( 17,19,21 ) и массивов ( 18,20,22 ) данного класса, за исключением случаев, когда выражение delete использовало форму :: delete которая обходит поиск в области видимости класса. Ключевое слово static является необязательным для объявлений этих функций: независимо от использования ключевого слова, функция освобождения всегда является статической функцией-членом.

Выражение delete ищет подходящую функцию освобождения памяти, начиная с области видимости класса (для массива поиск происходит в области видимости класса элемента массива) и переходит в глобальную область видимости, если не найдено подходящих членов, как обычно. Обратите внимание, что согласно правилам поиска имен , любые функции освобождения памяти, объявленные в области видимости класса, скрывают все глобальные функции освобождения памяти.

Если статический тип объекта, который удаляется, отличается от его динамического типа (например, при удалении полиморфного объекта через указатель на базовый класс), и если деструктор в статическом типе является виртуальным, форма удаления для одиночного объекта начинает поиск имени функции освобождения памяти с точки определения финального переопределителя его виртуального деструктора. Независимо от того, какая функция освобождения будет выполнена во время выполнения, статически видимая версия operator delete должна быть доступна для успешной компиляции. В других случаях, при удалении массива через указатель на базовый класс или при удалении через указатель на базовый класс с невиртуальным деструктором, поведение не определено.

Если перегрузка с одним аргументом ( 17,18 ) не предоставлена, но предоставлена перегрузка с поддержкой размера, принимающая std::size_t в качестве второго параметра ( 21,22 ) , то для обычного освобождения памяти вызывается форма с поддержкой размера, и среда выполнения C++ передает размер освобождаемого объекта в качестве второго аргумента. Если определены обе формы, вызывается версия без поддержки размера.

#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;
}

Возможный вывод:

custom delete for size 1
custom delete for size 18

Перегрузки operator delete и operator delete [ ] с дополнительными пользовательскими параметрами ("placement forms", ( 25,26 ) ) также могут быть определены как члены класса. Когда выражение placement new с ошибкой ищет соответствующую placement delete функцию для вызова, оно начинает поиск в области видимости класса перед изучением глобальной области видимости и ищет функцию с сигнатурой, соответствующей placement new :

#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';
    }
}

Вывод:

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

Если оператор delete на уровне класса operator delete является шаблонной функцией, он должен иметь возвращаемый тип void , первый аргумент void * , и должен иметь два или более параметров. Другими словами, только формы размещения могут быть шаблонами. Экземпляр шаблона никогда не является обычной функцией освобождения, независимо от его сигнатуры. Специализация шаблонного оператора delete выбирается с помощью вывода аргументов шаблона .

Примечания

Вызов специфичного для класса T :: operator delete в полиморфном классе — это единственный случай, когда статическая функция-член вызывается через динамическую диспетчеризацию.

Следующие функции должны быть потокобезопасными:

Вызовы этих функций, которые выделяют или освобождают определенную единицу памяти, происходят в едином общем порядке, и каждый такой вызов освобождения happens-before следующего выделения (если таковое имеется) в этом порядке.

(since C++11)
Макрос тестирования возможностей Значение Стандарт Возможность
__cpp_sized_deallocation 201309L (C++14) Sized deallocation
__cpp_impl_destroying_delete 201806L (C++20) Destroying operator delete (поддержка компилятора)
__cpp_lib_destroying_delete 201806L (C++20) Destroying operator delete (поддержка библиотеки)

Отчеты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение в опубликованной версии Корректное поведение
CWG 220 C++98 пользовательские функции освобождения памяти могли генерировать исключения генерация исключения из функции освобождения памяти
приводит к неопределённому поведению
CWG 1438 C++98 любое использование невалидного значения указателя было неопределённым поведением только разыменование и освобождение памяти являются таковыми
LWG 206 C++98 замена ( 2 ) не влияла на поведение по умолчанию для ( 10 ) поведение по умолчанию
изменяется соответствующим образом
LWG 298 C++98 замена ( 1 ) не влияла на поведение по умолчанию для ( 9 ) поведение по умолчанию
изменяется соответствующим образом
LWG 404 C++98 замены заменяемых функций освобождения
памяти могли быть объявлены inline
запрещено, диагностика не требуется
LWG 2458 C++14 перегрузки принимающие ( void * , std:: size_t , const
std:: nothrow_t & ) были специфицированы, но никогда не могли быть вызваны
удалены ложные перегрузки

Смотрите также

[static] (C++23)
освобождает память, ранее полученную от operator new
(публичная статическая функция-член std::generator<Ref,V,Allocator>::promise_type )
функции выделения памяти
(функция)
(устарело в C++17) (удалено в C++20)
освобождает неинициализированную память
(шаблон функции)
освобождает ранее выделенную память
(функция)