C ++-放置新的和D

什么是删除此处分配的所有内存的正确方法?

  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;

还是两者都一样?

Vink asked 2020-06-29T23:27:44Z
3个解决方案
50 votes

正确的方法是:

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

您只能使用delete运算符删除从new运算符收到的内容。 如果直接调用2944998483046171171函数,则还必须直接调用operator delete函数,并且还必须手动调用析构函数。

bdonlan answered 2020-06-29T23:28:18Z
25 votes

C ++中有两个独立的概念:

  1. 新/删除运算符。

  2. 新/删除表达式。

操作员分配和取消分配内存。 new表达式构造对象。 void * operator new (size_t, void * p) throw() { return p; }表达式有时会破坏对象并调用运算符。

为什么是“有时”? 因为这取决于表情。 裸露的全局void * operator new (size_t, void * p) throw() { return p; }首先调用operator-new分配内存,然后构造该对象。 全局delete调用析构函数并重新分配内存。 但是void operator delete (void *, void *) throw() { }delete的所有其他重载都不同:

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

仍然必须在匹配对中重载New / Delete运算符,因为当对象构造函数引发异常时,将调用匹配的delete运算符。 但是,没有自动的方法可以为已使用重载2944998896755540940992分配的对象调用析构函数,因此您必须自己执行此操作。

作为第一个也是最基本的示例,请考虑新放置的运算符,该运算符的强制形式为2944998896755555540992。因此,匹配的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
Kerrek SB answered 2020-06-29T23:29:14Z
2 votes

假设没有诸如::delete buf;之类的东西,则::版本是正确的,并将进行所有适当的清理。 为了安全起见,您可以说(

语言律师辩论材料如下。

5.3.5/1

delete-expression运算符销毁由new-expression创建的最派生对象(1.8)或数组。

删除表达式:

  • ::delete buf;opt :: cast-expression
  • ::delete buf;opt :: cast-expression

第一种选择用于非数组对象,第二种选择用于数组。 ...

5.3.5/2

...在第一个替代方案(删除对象)中,操作数::delete buf;的值可以是空指针,指向由先前的new表达式创建的非数组对象的指针或指向子对象(1.8)的指针 表示此类对象的基类(第10条)。 如果不是,则行为是不确定的。

因此,指针必须指向由new-expression创建的对象,该对象定义如下:

5.3.4/1

新表达式:

  • ::delete buf;opt :: new-placementopt新类型ID _new-initializer_opt
  • ::delete buf;opt :: new-placementopt ( type-id ) new-initializeropt

新的位置:

  • ::delete buf;表达式列表::

因此,“新的展示位置”确实算作新的表达式。 没有什么禁止删除表达式在那里。

而且,事实证明,尽管进行了自定义创建,但delete-expression确实可以正确地清理对象。

5.3.5/6-9

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

如果delete-expression的操作数的值不是空指针值,则delete-expression将调用释放函数(3.7.4.2)。 否则,不确定是否将调用释放函数。 [注意:无论对象的析构函数还是数组的某些元素引发异常,都会调用释放函数。 -尾注]

当在delete-expression中的关键字::delete buf;之前是一元::运算符时,全局释放功能将用于取消分配存储。

因此::delete buf;完全等同于:

try {
    buf->~Buffer();
} catch(...) {
    ::operator delete(mem);
    throw;
}
aschepler answered 2020-06-29T23:32:14Z
translate from https://stackoverflow.com:/questions/6783993/placement-new-and-delete