Vin*_*ink 47 c++ new-operator visual-c++ placement
删除此处分配的所有内存的正确方法是什么?
const char* charString = "Hello, World";
void *mem = ::operator new(sizeof(Buffer) + strlen(charString) + 1);
Buffer* buf = new(mem) Buffer(strlen(charString));
delete (char*)buf;
Run Code Online (Sandbox Code Playgroud)
要么
const char* charString = "Hello, World";
void *mem = ::operator new(sizeof(Buffer) + strlen(charString) + 1);
Buffer* buf = new(mem) Buffer(strlen(charString));
delete buf;
Run Code Online (Sandbox Code Playgroud)
还是他们都一样?
bdo*_*lan 51
正确的方法是:
buf->~Buffer();
::operator delete(mem);
Run Code Online (Sandbox Code Playgroud)
您只能向delete
操作员删除从new
操作员处收到的内容.如果直接调用该operator new
函数,还必须直接调用该operator delete
函数,并且还必须手动调用析构函数.
Ker*_* SB 25
C++中有两个独立的概念:
新/删除运算符.
新/删除表达式.
运算符分配和释放内存.该new
表达构建体的物体.的delete
表达有时会破坏一个对象,并调用操作者.
为什么"有时"?因为它取决于表达式.裸,全局new
首先调用operator-new来分配内存,然后构造对象; 全局delete
调用析构函数并释放内存.但所有其他重载new
和delete
不同:
新的/删除操作符仍然必须在匹配对中重载,因为当对象构造函数抛出异常时,将调用匹配的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
Run Code Online (Sandbox Code Playgroud)
正如其他答案中所解释的,更好、更明智的方法是
buf->~Buffer();
::operator delete(mem);
Run Code Online (Sandbox Code Playgroud)
然而,假设不存在诸如 之类的东西Buffer::operator delete
,该delete buf;
版本在技术上是没问题的,并且会进行所有相同的清理工作。为了避免这种Buffer::operator delete
可能性,你可以说::delete buf;
。
语言律师辩论材料如下。
5.3.5/1
删除表达式运算符会销毁由new 表达式创建的最派生对象 (1.8) 或数组。
删除表达式:
::
optdelete
强制转换表达式::
optdelete [ ]
强制转换表达式
第一种选择适用于非数组对象,第二种选择适用于数组。...
5.3.5/2
...在第一个替代方案(delete object)中, 的操作数的值可以是空指针、指向由先前的new 表达式
delete
创建的非数组对象的指针,或者指向表示的子对象(1.8)的指针此类对象的基类(第 10 条)。如果不是,则行为未定义。
因此,指针必须指向由new-expression创建的对象,其定义为:
5.3.4/1
新表达:
::
选择new
新放置选择 新类型ID 新初始化程序选择::
选择new
新放置选择(
类型ID)
新初始化程序选择
新位置:
(
表达式列表)
因此,“placement new”确实算作new-expression。没有什么禁止那里的删除表达式。
此外,事实证明,尽管是自定义创建的,但删除表达式确实正确地清理了对象。
5.3.5/6-9
如果删除表达式的操作数的值不是空指针值,则删除表达式将为要删除的对象或数组元素调用析构函数(如果有)。...
如果删除表达式的操作数的值不是空指针值,则删除表达式将调用释放函数(3.7.4.2)。否则,未指定是否会调用释放函数。[注意:无论对象或数组的某些元素的析构函数是否抛出异常,都会调用释放函数。-尾注]
当删除表达式
delete
中的关键字前面带有一元运算符时,将使用全局释放函数来释放存储。::
所以::delete buf;
完全等价于:
try {
buf->~Buffer();
} catch(...) {
::operator delete(mem);
throw;
}
::operator delete(mem);
Run Code Online (Sandbox Code Playgroud)