安置新的和删除
什么是正确的方法来删除这里分配的所有内存?
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;
或者他们都是一样的?
正确的方法是:
buf->~Buffer(); ::operator delete(mem);
您只能使用delete
操作员 delete
您new
操作员处收到的内容。 如果直接调用operator new
函数,还必须直接调用operator delete
函数,并且还必须手动调用析构函数。
在C ++中有两个单独的概念:
-
新的/删除操作符 。
-
新build/删除expression式 。
运算符分配和释放内存。 new
expression式构造对象。 delete
expression式有时会销毁一个对象并调用操作符。
为什么“有时”? 因为这取决于expression。 new
第一次调用operator-new分配内存然后构造对象; 全局delete
调用析构函数并释放内存。 但是new
和delete
所有其他重载是不同的:
- 重载的新expression式调用重载的新运算符来分配内存,然后继续构造对象。
- 但是,不存在重载的删除expression式,特别是没有“placement-delete”:相反,您必须手动调用析构函数。
New / Delete操作符仍然必须在匹配对中重载,因为匹配的delete操作符在对象构造函数抛出exception时被调用。 但是,没有自动的方法来调用已经被重载的new
运算符分配的对象的析构函数,所以你必须自己去做。
作为第一个也是最基本的例子,考虑放置新运算符 ,这是强制采取的formsvoid * operator new (size_t, void * p) throw() { return p; }
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
假设没有Buffer::operator delete
这样的东西, delete buf;
版本是正确的,将做所有适当的清理。 为了更安全一点,你可以说::delete buf;
。
语言律师的辩论材料如下。
5.3.5 / 1
delete-expression操作符销毁最大派生对象(1.8)或由new-expression创build的数组。
删除expression式:
::
optdelete
cast-expression::
optdelete [ ]
cast-expression第一种select是用于非数组对象,第二种用于数组。 …
5.3.5 / 2
…在第一种replace( 删除对象 )中,
delete
操作数的值可以是空指针,指向由前一个新expression式创build的非数组对象的指针或指向子对象(1.8)代表这样一个对象的基类(第10章)。 如果不是,则行为是不确定的。
所以指针必须指向一个由new-expression创build的对象,该对象被定义为:
5.3.4 / 1
新的expression式:
::
selectnew
新位置 select 新的types_新 _初始化_ select::
optnew
新展示位置 opt(
type-id)
new-initializer opt新布局:
(
expression列表)
所以一个“安置新的”算作一个新的expression 。 没有什么禁止在那里的删除expression 。
此外,事实certificate,尽pipe自定义创build, 删除expression式完全正确地清理对象。
5.3.5 / 6-9
如果delete-expression的操作数的值不是空指针值,则delete-expression将调用该对象的析构函数(如果有)或要删除的数组的元素。 …
如果delete-expression的操作数的值不是空指针值,则delete-expression将调用一个释放函数 (3.7.4.2)。 否则,未指定是否调用释放函数。 [ 注意:无论对象的析构函数还是数组的某个元素抛出exception,都会调用释放函数。 – 结束注意 ]
当delete-expression中的关键字
delete
在unary::
运算符前面时,全局释放函数用于释放存储。
所以::delete buf;
完全等同于:
try { buf->~Buffer(); } catch(...) { ::operator delete(mem); throw; }