operator delete , operator delete[]
|
Определено в заголовке
<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 выражениями для освобождения памяти после деструкции (или неудачного конструирования) объектов с динамической продолжительностью хранения. Они также могут быть вызваны с использованием обычного синтаксиса вызова функций.
-
Если
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 [ ] .
Перегрузки ( 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 ) являются заменяемыми . Эффекты версий по умолчанию следующие:
Глобальная замена
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)
|
освобождает неинициализированную память
(шаблон функции) |
|
освобождает ранее выделенную память
(функция) |