如果我做了
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
状态:
delete操作数的值可以是…指向由前一个new-expression创建的非数组对象的指针。
Placement new是new-expression的类型。[expr.new]/1
:
<我>新的表达式:
:: <我><子>选择子>新<我>新的广告<子>选择子> new-type-id new-initializer <子>选择子>
:: <我><子>选择子>新<我>新的广告<子>选择子> (<我> id类型) <我> new-initializer <子>选择子>我>我>我>我>我>我>我>
delete
定义为对对象的析构函数的调用,然后对内存的释放函数的调用。[expr.delete]/6,7
:
…delete表达式将调用对象的析构函数(如果有的话)…
…delete表达式将调用一个释放函数…
只要释放函数匹配分配函数(它应该匹配,只要您没有为您的类重载operator delete
),那么这些都应该定义得很好。
[Revised]一般不可以,您只能一般delete
使用匹配的普通new
表达式获得的东西。否则,由您来保证释放函数与分配函数匹配(因此,使用::delete p;
将是更安全的通用解决方案,假设您的原始operator new
位于全局命名空间中)。特别是当有问题的类(或其派生类之一)重载operator new
时,您必须小心。
由于您使用的是位置-new表达式来创建*p
,并且由于没有"位置-delete表达式"这样的东西,因此您必须手动销毁对象,然后释放内存:
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)