Is `new (this) MyClass();` undefined behaviour aft

2019-01-20 09:06发布

In this question of mine, @DeadMG says that reinitializing a class through the this pointer is undefined behaviour. Is there any mentioning thereof in the standard somewhere?

Example:

#include <iostream>

class X{
  int _i;
public:  
  X() : _i(0) { std::cout << "X()\n"; }
  X(int i) : _i(i) { std::cout << "X(int)\n"; }

  ~X(){ std::cout << "~X()\n"; }

  void foo(){
    this->~X();
    new (this) X(5);
  }

  void print_i(){
    std::cout << _i << "\n";
  }
};

int main(){
  X x;
  x.foo();
  // mock random stack noise
  int noise[20];
  x.print_i();
}

Example output at Ideone (I know that UB can also be "seemingly correct behaviour").
Note that I did not call the destructor outside of the class, as to not access an object whose lifetime has ended. Also note, that @DeadMG says that directly calling the destructor is okay as-long-as it's called once for every constructor.

2条回答
Animai°情兽
2楼-- · 2019-01-20 09:26

That would be okay if it didn't conflict with stack unwinding.

You destroy the object, then reconstruct it via the pointer. That's what you would do if you needed to construct and destroy an array of objects that don't have a default constructor.

The problem is this is exception unsafe. What if calling the constructor throws an exception and stack is unwound and the destructor is called for the second time?

{
   X x;
   x.foo(); // here ~X succeeds, then construction fails
} //then the destructor is invoked for the second time.

That aspect specifically would be undefined behavior.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-01-20 09:30

Apart from @sharptooth's answer. I am just wondering for 2 more cases. At least they are worth mentioning.

(1) If the foo() was invoked using a pointer on heap which was allocated using malloc(). The constructor is not called. Can it be safe ?

(2) What if the derived class is calling foo(). Will it be a good behavior ? e.g.

struct Y : X {};  // especially when there is virtual ~X()
int main ()
{
  Y y;
  y.foo();
}
查看更多
登录 后发表回答