删除此处分配的所有内存的正确方法是什么?
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;
或两者都相同?
答案 0 :(得分:46)
正确的方法是:
buf->~Buffer();
::operator delete(mem);
您只能使用delete
运算符删除从new
运算符收到的内容。如果直接调用operator new
函数,则还必须直接调用operator delete
函数,并且还必须手动调用析构函数。
答案 1 :(得分:24)
C ++中有两个独立的概念:
新/删除运算符。
新建/删除表达式。
运算符分配和释放内存。 new
表达式构造对象。 delete
表达式有时会破坏对象并调用运算符。
为什么“有时”?因为它取决于表达式。裸,全局new
首先调用operator-new来分配内存,然后构造对象;全局delete
调用析构函数并释放内存。但new
和delete
的所有其他重载都不同:
新的/删除运算符仍然必须在匹配对中重载,因为当对象构造函数抛出异常时会调用匹配的删除运算符。但是,没有自动方法为已经使用重载new
运算符分配的对象调用析构函数,因此您必须自己执行此操作。
作为第一个也是最基本的示例,请考虑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
答案 2 :(得分:2)
假设没有Buffer::operator delete
这样的东西,delete buf;
版本是正确的,并将进行所有适当的清理。为了更安全一点,您可以说::delete buf;
。
语言 - 律师辩论材料如下。
5.3.5 / 1
delete-expression 运算符会销毁由 new-expression 创建的派生程度最高的对象(1.8)或数组。
删除表达式:
::
optdelete
cast-expression::
optdelete [ ]
cast-expression第一种方法是非数组对象,第二种方法是数组。 ...
5.3.5 / 2
...在第一个备选方案(删除对象)中,
delete
的操作数值可能是空指针,指向由非创建的非数组对象的指针前面的 new-expression ,或指向表示此类对象的基类的子对象(1.8)的指针(第10条)。如果不是,则行为未定义。
因此指针必须指向由 new-expression 创建的对象,该对象已定义:
5.3.4 / 1
new表达式:
::
optnew
new-placement opt < / sub> new-type-id _new-initializer_ opt::
optnew
new-placement opt < / sub>(
type-id)
new-initializer opt新放置:
(
表达式列表)
所以“placement new”确实算作 new-expression 。没有什么可以禁止 delete-expression 。
此外,事实证明,无论自定义创建, delete-expression 都能正确清理对象。
5.3.5 / 6-9
如果 delete-expression 的操作数值不是空指针值, delete-expression 将调用该对象的析构函数(如果有)或者要删除的数组元素。 ...
如果 delete-expression 的操作数值不是空指针值, delete-expression 将调用释放函数(3.7.4.2)。否则,未指定是否将调用释放功能。 [注意:无论对象的析构函数或数组的某个元素是否引发异常,都会调用释放函数。 - 结束记录]
当 delete-expression 中的关键字
delete
前面有一元::
运算符时,全局释放函数用于释放存储空间。
所以::delete buf;
完全等同于:
try {
buf->~Buffer();
} catch(...) {
::operator delete(mem);
throw;
}