C++ 放置新建和删除

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6783993/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 20:41:02  来源:igfitidea点击:

placement new and delete

c++visual-c++new-operatorplacement

提问by Vink

What is the right method to delete all the memory allocated here?

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

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

  delete (char*)buf;

OR

或者

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

  delete buf;

or are they both same?

或者他们都一样?

回答by bdonlan

The correct method is:

正确的方法是:

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

You can only delete with the deleteoperatorwhat you received from the newoperator. If you directly call the operator newfunction, you must also directly call the operator deletefunction, and must manually call the destructor as well.

您只能用deletedelete操作符,你从接收什么new操作。如果直接调用operator new函数,也必须直接调用operator delete函数,并且必须手动调用析构函数。

回答by Kerrek SB

There are two separate notions in C++:

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

  1. The new/delete operators.

  2. New/Delete expressions.

  1. 新建/删除操作符

  2. 新建/删除表达式

The operators allocate and deallocate memory. The newexpression constructs objects. The deleteexpression sometimes destroys an object and calls the operator.

运算符分配和释放内存。该new表达构建体的物体。该delete表达式有时会破坏一个对象并调用运算符。

Why "sometimes"? Because it depends on the expression. The naked, global newfirst calls operator-new to allocate memory and then constructs the object; the global deletecalls the destructor and deallocates the memory. But all other overloads of newand deleteare different:

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

  • An overloaded new expressioncalls an overloaded new operatorto allocate memory and then proceeds to construct the object.
  • However, there is no such thing as an overloaded delete expression, in particular there is no "placement-delete": Instead, you have to call the destructor manually.
  • 重载的 new表达式调用重载的 new运算符来分配内存,然后继续构造对象。
  • 但是,没有重载删除表达式这样的东西,特别是没有“放置删除”:相反,您必须手动调用析构函数。

New/Delete operators still have to be overloaded in matching pairs, because the matching delete operator is called when an object constructor throws an exception. However, there is no automatic way to invoke the destructor for an object that has been allocated with an overloaded newoperator, so you have to do that yourself.

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

As the first and most basic example, consider the placement-new operator, which is mandated to take the form void * operator new (size_t, void * p) throw() { return p; }. The matching deleteoperator is thus mandated to do nothing: void operator delete (void *, void *) throw() { }. Usage:

作为第一个也是最基本的例子,考虑placement-new运算符,它被强制采用形式 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

回答by aschepler

Assuming there's no such thing as Buffer::operator delete, the delete buf;version is correct and will do all the appropriate cleanup. To be a bit safer, you can say ::delete buf;.

假设没有这样的东西Buffer::operator deletedelete buf;版本是正确的,并且会做所有适当的清理工作。为了更安全,你可以说::delete buf;.

Language-lawyer debate material follows.

语言律师辩论材料如下。

5.3.5/1

5.3.5/1

The delete-expressionoperator destroys a most derived object (1.8) or array created by a new-expression.

delete-expression:

  • ::optdeletecast-expression
  • ::optdelete [ ]cast-expression

The first alternative is for non-array objects, and the second is for arrays. ...

delete表达式运算符破坏由创建的最派生对象(1.8)或阵列新表达

删除表达式:

  • ::选择转换delete表达式
  • ::选择转换delete [ ]表达式

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

5.3.5/2

5.3.5/2

... In the first alternative (delete object), the value of the operand of deletemay be a null pointer, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (1.8) representing a base class of such an object (Clause 10). If not, the behavior is undefined.

...在第一个选择(删除对象)中,操作数的值delete可能是一个空指针,一个指向由前一个new 表达式创建的非数组对象的指针,或一个指向表示子对象(1.8)的指针此类对象的基类(第 10 条)。如果不是,则行为未定义。

So the pointer must point at an object created by a new-expression, which is defined:

所以指针必须指向一个由new-expression创建的对象,它的定义是:

5.3.4/1

5.3.4/1

new-expression:

  • ::optnewnew-placementoptnew-type-id_new-initializer_opt
  • ::optnewnew-placementopt(type-id)new-initializeropt

new-placement:

  • (expression-list)

新表达式:

  • ::optnewnew-placement optnew-type-id_new-initializer_opt
  • ::optnewnew-placement opt(type-id )new-initializer opt

新安置:

  • (表达式列表)

So a "placement new" does count as a new-expression. Nothing forbidding a delete-expressionthere.

所以一个“placement new”确实算作一个new-expression。没有禁止删除表达式

Also, it turns out the delete-expressiondoes exactly the right things to clean up the object despite the custom creation.

此外,事实证明,尽管自定义创建,delete-expression确实做了正确的事情来清理对象。

5.3.5/6-9

5.3.5/6-9

If the value of the operand of the delete-expressionis not a null pointer value, the delete-expressionwill invoke the destructor (if any) for the object or the elements of the array being deleted. ...

If the value of the operand of the delete-expressionis not a null pointer value, the delete-expressionwill call a deallocation function(3.7.4.2). Otherwise, it is unspecified whether the deallocation function will be called. [Note:The deallocation function is called regardless of whether the destructor for the object or some element of the array throws an exception. - end note]

When the keyword deletein a delete-expressionis preceded by the unary ::operator, the global deallocation function is used to deallocate the storage.

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

如果删除表达式的操作数的值不是空指针值,则删除表达式将调用释放函数(3.7.4.2)。否则,未指定是否将调用释放函数。[注意:无论对象的析构函数还是数组的某个元素的析构函数是否抛出异常,都会调用释放函数。-尾注]

当关键字delete在一个delete表达式由一元之前::操作者,全球解除分配功能用于解除分配的存储。

So ::delete buf;is entirely equivalent to:

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

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