Если я сделаю
struct MyStruct { ~MyStruct() { } };
void *buffer = operator new(1024);
MyStruct *p = new(buffer) MyStruct();
// ...
delete p; // <---------- is this okay?
это delete
гарантированно позаботится о и то и другое призвание ~MyStruct()
так же как operator delete
?
delete p
эквивалентно
p->~MyStruct();
operator delete(p);
если MyStruct
имеет альтернативу operator delete
поэтому ваш пример должен быть четко определен с ожидаемой семантикой.
[expr.delete]/2
состояния:
значение операнда удаления может быть … указатель на объект, не являющийся массивом, созданный предыдущим новое выражение.
Размещение нового типа новое выражение. [expr.new]/1
:
новое выражение:
::выбирать новый новое размещениевыбирать new-type-id new-initializerвыбирать
::выбирать новый новое размещениевыбирать ( тип-идентификатор ) новый инициализаторвыбирать
delete
определяется как вызов деструктора объекта, а затем вызов функции освобождения памяти. [expr.delete]/6,7
:
… удалить выражение вызовет деструктор (если есть) для объекта …
… удалить выражение вызовет функцию освобождения …
Пока функция освобождения совпадает с функцией распределения (что и должно быть, если вы не перегружены operator delete
для вашего класса), то все это должно быть четко определено.
delete
то, что было получено с соответствующей равнине new
выражение. В противном случае вы должны гарантировать, что функция освобождения соответствует функции распределения (поэтому использование ::delete p;
было бы более безопасным общим решением, предполагая, что ваш оригинал operator new
был в глобальном пространстве имен). В частности, когда рассматриваемый класс (или один из его производных классов) перегружается operator new
ты должен быть осторожен.
Так как вы используете новое выражение для создания *p
и поскольку не существует такого понятия, как «выражение размещения-удаления», необходимо уничтожить объект вручную, а затем освободить память:
p->~MyStruct();
operator delete(buffer);
Нет, обычно вы не должны вызывать delete (в некоторых случаях, например, когда оператор 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)