安置新的和删除

什么是正确的方法来删除这里分配的所有内存?

const char* charString = "Hello, World"; void *mem = ::operator new(sizeof(Buffer) + strlen(charString) + 1); Buffer* buf = new(mem) Buffer(strlen(charString)); delete (char*)buf; 

要么

  const char* charString = "Hello, World"; void *mem = ::operator new(sizeof(Buffer) + strlen(charString) + 1); Buffer* buf = new(mem) Buffer(strlen(charString)); delete buf; 

或者他们都是一样的?

正确的方法是:

 buf->~Buffer(); ::operator delete(mem); 

您只能使用delete 操作员 deletenew 操作员处收到的内容。 如果直接调用operator new函数,还必须直接调用operator delete函数,并且还必须手动调用析构函数。

在C ++中有两个单独的概念:

  1. 新的/删除操作符

  2. 新build/删除expression式

运算符分配和释放内存。 newexpression式构造对象。 deleteexpression式有时会销毁一个对象并调用操作符。

为什么“有时”? 因为这取决于expression。 new第一次调用operator-new分配内存然后构造对象; 全局delete调用析构函数并释放内存。 但是newdelete所有其他重载是不同的:

  • 重载的新expression式调用重载的新运算符来分配内存,然后继续构造对象。
  • 但是,不存在重载的删除expression式,特别是没有“placement-delete”:相反,您必须手动调用析构函数。

New / Delete操作符仍然必须在匹配对中重载,因为匹配的delete操作符在对象构造函数抛出exception时被调用。 但是,没有自动的方法来调用已经被重载的new运算符分配的对象的析构函数,所以你必须自己去做。

作为第一个也是最基本的例子,考虑放置新运算符 ,这是强制采取的formsvoid * operator new (size_t, void * p) throw() { return p; } void * operator new (size_t, void * p) throw() { return p; } 。 因此,匹配的delete操作符被强制执行: void operator delete (void *, void *) throw() { } 。 用法:

 void * p = ::operator new(5); // allocate only! T * q = new (p) T(); // construct q->~T(); // deconstruct: YOUR responsibility // delete (p) q; <-- does not exist!! It would invoke the following line: ::operator delete(p, q); // does nothing! ::operator delete(q); // deallocate 

假设没有Buffer::operator delete这样的东西, delete buf; 版本是正确的,将做所有适当的清理。 为了更安全一点,你可以说::delete buf;

语言律师的辩论材料如下。

5.3.5 / 1

delete-expression操作符销毁最大派生对象(1.8)或由new-expression创build的数组。

删除expression式:

  • :: opt delete cast-expression
  • :: opt delete [ ] cast-expression

第一种select是用于非数组对象,第二种用于数组。 …

5.3.5 / 2

…在第一种replace( 删除对象 )中, delete操作数的值可以是空指针,指向由前一个新expression式创build的非数组对象的指针或指向子对象(1.8)代表这样一个对象的基类(第10章)。 如果不是,则行为是不确定的。

所以指针必须指向一个由new-expression创build的对象,该对象被定义为:

5.3.4 / 1

新的expression式:

  • :: select new 新位置 select 新的types_新 _初始化_ select
  • :: opt new 新展示位置 opt ( type-id ) new-initializer opt

新布局:

  • ( expression列表 )

所以一个“安置新的”算作一个新的expression 。 没有什么禁止在那里的删除expression

此外,事实certificate,尽pipe自定义创build, 删除expression式完全正确地清理对象。

5.3.5 / 6-9

如果delete-expression的操作数的值不是空指针值,则delete-expression将调用该对象的析构函数(如果有)或要删除的数组的元素。 …

如果delete-expression的操作数的值不是空指针值,则delete-expression将调用一个释放函数 (3.7.4.2)。 否则,未指定是否调用释放函数。 [ 注意:无论对象的析构函数还是数组的某个元素抛出exception,都会调用释放函数。 – 结束注意 ]

delete-expression中的关键字delete在unary ::运算符前面时,全局释放函数用于释放存储。

所以::delete buf; 完全等同于:

 try { buf->~Buffer(); } catch(...) { ::operator delete(mem); throw; }