在使用operator new的展示位置删除结果上调用delete好吗?

Meh*_*dad 12 c++ placement-new new-operator delete-operator

如果我做

struct MyStruct { ~MyStruct() { } };

void *buffer = operator new(1024);
MyStruct *p = new(buffer) MyStruct();
// ...
delete p;     //    <---------- is this okay?
Run Code Online (Sandbox Code Playgroud)

delete保证照顾两个呼叫~MyStruct() 以及 operator delete

Man*_*rse 13

delete p 相当于

p->~MyStruct();
operator delete(p);
Run Code Online (Sandbox Code Playgroud)

除非MyStruct有替代方案operator delete,因此您的示例应该使用预期的语义进行良好定义.

[expr.delete]/2 状态:

delete的操作数的值可以是......指向由前一个new-expression创建的非数组对象的指针.

Placement new是一种new-expression.[expr.new]/1:

新表达:
    :: 选择 新放置选择新型-ID的新初始值设定选择
    :: 选择 新放置选择(类型-ID)的新初始值设定选择

delete被定义为对对象的析构函数的调用,然后调用内存的释放函数.[expr.delete]/6,7:

... delete-expression将为对象调用析构函数(如果有的话)...

... delete-expression将调用释放函数...

只要解除分配函数与分配函数匹配(只要你没有operator delete为你的类重载,它应该是这样),那么这应该都是明确定义的.

  • 嗯.您还必须注意,在`operator new`的返回值之后,不允许在实现之间添加填充.(事实并非如此; C++11§5.3.4/ 10.)即便如此,我仍然对此感到不安.似乎没有不可避免的用例,因为`dynamic_cast <void*>()`即使你不知道动态类型,也会获得最多派生的指针. (2认同)

Ker*_* SB 12

[修订]一般情况下都不行,你通常只能delete用匹配的普通new表达式获得.否则,您可以保证解除分配函数与分配函数匹配(因此::delete p;,假设您的原始文件operator new位于全局命名空间中,则使用更安全的通用解决方案).特别是当有问题的类(或其派生类之一)超载时,operator new你必须要小心.

由于您正在使用placement-new表达式来创建*p,并且由于没有"placement-delete expression"这样的东西,您必须手动销毁该对象然后释放内存:

p->~MyStruct();

operator delete(buffer);
Run Code Online (Sandbox Code Playgroud)

  • 除了下意识之外"这很奇怪且与记忆有关,所以它必须是UB",你有什么证据可以证明这一点? (3认同)
  • @Mehrdad:但请注意,这种设计并不安全:稍后通过向课程添加内容,有人可能会远程破坏您的代码,而您永远不会知道.只要做正确的事,你就可以省去所有这些麻烦.(*实际*正确的事情永远不会在客户端代码中自己拼出"新",而是使用像allocators和`allocate_shared`之​​类的东西.) (3认同)