Является ли вызов 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)