Является ли вызов delete по результату удаления места размещения, который использовал новый оператор?
Если я делаю
struct MyStruct { ~MyStruct() { } };
void *buffer = operator new(1024);
MyStruct *p = new(buffer) MyStruct();
// ...
delete p; // <---------- is this okay?
является delete
, гарантированным как для вызова ~MyStruct()
, так и для operator delete
?
Ответы
Ответ 1
delete p
эквивалентно
p->~MyStruct();
operator delete(p);
если MyStruct
не имеет альтернативы operator delete
, поэтому ваш пример должен быть хорошо определен с ожидаемой семантикой.
[expr.delete]/2
:
значение операнда delete может быть... указателем на объект без массива, созданный предыдущим новым выражением.
Размещение new - это тип нового выражения. [expr.new]/1
:
<я > новое выражение:
:: opt new новый тип размещения opt нового типа -id new-initializer opt
:: opt new новое размещение opt (type-id) new-initializer opt
delete
определяется как вызов деструктора объекта, а затем вызов функции освобождения памяти. [expr.delete]/6,7
:
... delete-expression будет вызывать деструктор (если есть) для объекта...
... delete-expression будет вызывать функцию деаллокации...
Пока функция освобождения соответствует функции выделения (она должна, если вы не перегружаете operator delete
для своего класса), тогда это должно быть хорошо определено.
Ответ 2
[Пересмотрено] Это не нормально, и вы можете только delete
сделать что-то, полученное с помощью соответствующего простого выражения new
. В противном случае вы можете гарантировать, что функция освобождения соответствует функции распределения (поэтому использование ::delete p;
будет более безопасным общим решением, если ваш исходный operator new
был в глобальном пространстве имен). В частности, когда рассматриваемый класс (или один из его производных классов) перегружает operator new
, вы должны быть осторожны.
Поскольку для создания *p
используется выражение размещения-new, и поскольку нет такого понятия, как выражение "размещение-удаление", вам необходимо уничтожить объект вручную, а затем освободить память:
p->~MyStruct();
operator delete(buffer);
Ответ 3
Нет, вы вообще не должны вызывать delete (в некоторых случаях, например, при удалении оператора, это может быть нормально).
char *buffer = new char[1024];
MyStruct *p = new(buffer) MyStruct(); //placement new "i'm just calling constructor"
p->~MyStruct(); //destroy the object.
//delete p; // WHAT? even if you override operator delete it may be opaque to reader.
delete [] buffer; // THIS DELETE IS OK (if you have first destroyed MyStruct)