operator delete, operator delete[]
| Определён в заголовке <new>
|
||
| Заменяемые обычные функции освобождения |
||
void operator delete ( void* ptr ) throw();
|
(1) | (до C++11) |
void operator delete ( void* ptr ) noexcept;
|
(начиная с C++11) | |
void operator delete[]( void* ptr ) throw();
|
(2) | (до 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) |
| Заменяемые размещающие функции освобождения |
||
void operator delete ( void* ptr, const std::nothrow_t& tag ) throw();
|
(9) | (до C++11) |
void operator delete ( void* ptr, const std::nothrow_t& tag ) noexcept;
|
(начиная с C++11) | |
void operator delete[]( void* ptr, const std::nothrow_t& tag ) throw();
|
(10) | (до 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) |
| Невыделяющие размещающие функции освобождения |
||
void operator delete ( void* ptr, void* place ) throw();
|
(13) | (до C++11) |
void operator delete ( void* ptr, void* place ) noexcept;
|
(начиная с C++11) | |
void operator delete[]( void* ptr, void* place ) throw();
|
(14) | (до 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[] выражениями и размещающими new выражениями для освобождения памяти после уничтожения (или неудачного конструирования) объектов с динамическим сроком хранения. Они также могут быть вызваны с помощью обычного синтаксиса вызова функций.
delete и delete[] выражениями. Инвалидирует любой ненулевой ptr.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[].
- Для
new выражениями, которые вызвали невыделяющую размещающую функцию выделения, когда любая часть инициализации в выражении завершается выбросом исключения. Не выполняет никаких действий.delete, delete[] и размещающими new выражениями.delete выражения не выполняют деструктор для *ptr перед вызовом operator delete. Вместо этого прямой вызов деструктора, например через ptr->~T();, становится ответственностью этого operator delete.Перегрузки (1-8) неявно объявляются в каждой единице трансляции, даже если заголовок <new> не включён.
См. delete выражение для критериев выбора перегрузки.
Параметры
| 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 ) являются заменяемыми . Эффекты версий по умолчанию следующие:
Глобальная замена
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)
|
освобождает неинициализированную память
(шаблон функции) |
|
освобождает ранее выделенную память
(функция) |