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
placement new and delete
提问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 delete
operatorwhat you received from the new
operator. If you directly call the operator new
function, you must also directly call the operator delete
function, 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++ 中有两个独立的概念:
The new/delete operators.
New/Delete expressions.
新建/删除操作符。
新建/删除表达式。
The operators allocate and deallocate memory. The new
expression constructs objects. The delete
expression sometimes destroys an object and calls the operator.
运算符分配和释放内存。该new
表达构建体的物体。该delete
表达式有时会破坏一个对象并调用运算符。
Why "sometimes"? Because it depends on the expression. The naked, global new
first calls operator-new to allocate memory and then constructs the object; the global delete
calls the destructor and deallocates the memory. But all other overloads of new
and delete
are different:
为什么是“有时”?因为这取决于表达。裸的,全局new
先调用operator-new分配内存,然后构造对象;全局delete
调用析构函数并释放内存。但在所有其他重载new
和delete
是不同的:
- 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 new
operator, 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 delete
operator 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 delete
,delete 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:
::
optdelete
cast-expression::
optdelete [ ]
cast-expressionThe 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
delete
may 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:
::
optnew
new-placementoptnew-type-id_new-initializer_opt::
optnew
new-placementopt(
type-id)
new-initializeroptnew-placement:
(
expression-list)
新表达式:
::
optnew
new-placement optnew-type-id_new-initializer_opt::
optnew
new-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
delete
in 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;
}