Bla*_*ger 6 c++ memory-management placement-new language-lawyer delete-operator
我想知道这段代码是否合法:
delete new (operator new(1)) char;
Run Code Online (Sandbox Code Playgroud)
此代码执行相同的操作,但不在从放置 new 获得的指针上使用删除表达式:
void* p = operator new(1);
new (p) char;
delete static_cast<char*>(p);
Run Code Online (Sandbox Code Playgroud)
[expr.delete#2]的标准规则:
在单对象删除表达式中,delete 操作数的值可以是空指针值、由先前的非数组 new 表达式产生的指针值,或者指向由以下方法创建的对象的基类子对象的指针:如此新的表达方式。如果不是,则行为未定义。在数组删除表达式中,delete 操作数的值可以是空指针值或由前一个数组 new-expression 产生的指针值。68 如果不是,则行为未定义。
该标准并没有说 new-express 不包括放置 new。所以我认为按照标准,第一段代码应该是合法的,但第二段代码应该是非法的。我的想法正确吗?
为什么标准这么说?调用operator new并在其上构造一个对象,其作用与new表达式几乎相同,但在获得的指针上使用delete表达式不一定合法。
对于分配数组,标准似乎允许这样做:
delete[] new (operator new[](2)) char[2];
Run Code Online (Sandbox Code Playgroud)
但由于未指定的开销,它应该是非法的。
为什么标准允许这样做?
编辑:根据[intro.object]/13:
对名为operator new 或operator new[] 的函数的任何隐式或显式调用都会在返回的存储区域中隐式创建对象,并返回指向合适的已创建对象的指针。
所以我什至可以编写以下代码:
delete static_cast<char*>(operator new(1));
Run Code Online (Sandbox Code Playgroud)
它销毁隐式创建的char对象并释放内存,执行与上面示例相同的操作。但根据标准,它绝对是非法的,因为没有使用 new 表达式。
为什么标准不允许这样做?
delete new (operator new(1)) char;看起来确实是合法的。正如您所说,该标准对于新的放置没有任何例外。
你的第二个例子也是合法的:
void* p = operator new(1);
new (p) char;
delete static_cast<char*>(p);
Run Code Online (Sandbox Code Playgroud)
让我们逐步了解一下发生的情况。对 的operator new调用隐式创建一个对象并返回指向该对象1char的指针。所以一开始就指向一个对象。放置 new 表达式在旧对象上构造一个新对象,结束旧对象的生命周期;根据抽象机的规则,这神奇地改变了such 的值,使其指向这个新对象;请参阅[basic.life]/8。最后,返回指向同一对象的指针。也就是说,该指针与放置 new 返回的指针具有相同的值。因此,如果第一个示例有效,那么这个示例也有效。pcharcharpstatic_cast<char*>(p)char
请注意,[expr.delete]/2 并不表明为了使操作数有效,从表达式到现在要删除的值delete必须存在某种有效的“监管链” 。它只是说“...由先前的非数组新表达式new产生的指针值...”指针的值才是最重要的。在第二个示例中,由于 [basic.life]/8,它与从放置 new 返回的指针具有相同的值。p
关于你的第三个例子,delete[] new (operator new(2)) char[2];我同意它不应该是合法的。我建议提交缺陷报告。
1请参阅[intro.object]/13。