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

Ben*_*igt 12 c++ placement-new language-lawyer delete-operator

我确信这段代码应该是非法的,因为它显然不会起作用,但它似乎被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
Run Code Online (Sandbox Code Playgroud)

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

还有一个数组形式:

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
Run Code Online (Sandbox Code Playgroud)

这是我能找到的最接近的问题.

编辑:我只是不买,该标准的语言限制参数函数的参数void ::operator delete(void*)以任何有意义的方式适用于操作数deletedelete表达式.在最好的情况,两者之间的连接是极其脆弱的,以及一些表达式允许作为操作数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;
}
Run Code Online (Sandbox Code Playgroud)

我希望这表明指针是否可以传递void operator delete(void*)给与该指针是否可以用作操作数无关delete.

Joh*_*itb 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更正,所以它不能再被误认了.


Fré*_*idi 3

编译器并不真正关心p来自放置调用的new内容,因此它不会阻止您delete在对象上发出。这样,您的示例就可以被认为是“合法的”。

但这是行不通的,因为delete无法显式调用“放置”运算符。仅当构造函数抛出异常时才会隐式调用它们,以便析构函数可以运行。