对从放置new获取的指针使用operator delete的合法性

时间:2010-12-11 18:24:09

标签: c++ language-lawyer delete-operator placement-new

我确信这段代码应该是非法的,因为它显然不会起作用,但它似乎被C ++ 0x FCD所允许。

class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X(); // according to the standard, the RHS is a placement-new expression
::operator delete(p); // definitely wrong, per litb's answer
delete p; // legal?  I hope not

也许你们中的一位语言律师可以解释标准是如何禁止的。

还有一个数组形式:

class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X[1]; // according to the standard, the RHS is a placement-new expression
::operator delete[](p); // definitely wrong, per litb's answer
delete [] p; // legal?  I hope not

This is the closest question我找到了。

编辑:我只是不买标准的限制函数void ::operator delete(void*)的参数的语言以任何有意义的方式应用于 delete-expression 。最好的情况是,两者之间的连接非常脆弱,并且许多表达式 允许作为delete的操作数,这些操作数无效传递给{{ 1}}。例如:

delete

我希望这表明指针是否可以传递给void ::operator delete(void*)与是否可以将同一指针用作struct A { virtual ~A() {} }; struct B1 : virtual A {}; struct B2 : virtual A {}; struct B3 : virtual A {}; struct D : virtual B1, virtual B2, virtual B3 {}; struct E : virtual B3, virtual D {}; int main( void ) { B3* p = new E(); void* raw = malloc(sizeof (D)); B3* p2 = new (raw) D(); ::operator delete(p); // definitely UB delete p; // definitely legal ::operator delete(p2); // definitely UB delete p2; // ??? return 0; } 的操作数无关。

4 个答案:

答案 0 :(得分:7)

标准规则在[basic.stc.dynamic.deallocation] p3

  

否则,标准库中提供给operator delete(void*)的值应该是之前调用标准库中operator new(size_t)operator new(size_t, const std::nothrow_t&)返回的值之一,以及值提供给标准库中的operator delete[](void*)应该是之前调用标准库中operator new[](size_t)operator new[](size_t, const std::nothrow_t&)返回的值之一。

您的delete来电将调用图书馆operator delete(void*),除非您已覆盖它。既然你没有说过什么,我会假设你没有。

上面的“应该”应该是“行为未定义,如果不是”,所以它不会被误认为是可诊断的规则,而不是[lib.res.on.arguments] p1。这已被n3225更正,所以它不能再被误认为了。

答案 1 :(得分:3)

编译器并不关心p来自展示位置new,因此它不会阻止您在对象上发出delete。通过这种方式,您的示例可以被视为“合法”。

但这不起作用,因为无法显式调用“placement delete”运算符。只有在构造函数抛出时才会隐式调用它们,因此析构函数可以运行。

答案 2 :(得分:2)

如果

,我想你可能会侥幸逃脱它(在特定的编译器上)
  1. new / delete是根据malloc / free
  2. 实施的
  3. placement new实际上使用相同的机制来跟踪与分配相关联的析构函数作为标准new,以便对delete的调用可以找到正确的析构函数。
  4. 但是它无法移动或安全。

答案 3 :(得分:2)

我在标准的图书馆部分找到了这个,这与尽可能反直觉的位置(IMO)有关:

C ++ 0x FCD(和n3225草案)第18.6.1.3节,[new.delete.placement]

  

这些函数是保留的,是C ++   程序可能没有定义那些功能   取代标准中的版本   C ++库(17.6.3)。规定   (3.7.4)不适用于这些   预留的经营者安置形式   new和operator delete。

void*  operator  new(std::size_t  size,  void*  ptr)  throw();
void*  operator  new[](std::size_t  size,  void*  ptr)  throw();
void  operator  delete(void*  ptr,  void*)  throw();
void  operator  delete[](void*  ptr,  void*)  throw();

但是,定义传递给delete的合法表达式的部分是5.3.5,而不是3.7.4。