9

この私の質問では、@DeadMGは、thisポインターを介してクラスを再初期化することは未定義の動作であると言います。どこかの規格に言及されていますか?

例:

#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();
}

Ideone での出力例(UB も「一見正しい動作」になる可能性があることはわかっています)。
有効期間が終了したオブジェクトにアクセスしないように、クラスの外部でデストラクタを呼び出さなかったことに注意してください。また、@DeadMG は、コンストラクターごとに 1 回呼び出される限り、デストラクタを直接呼び出すことは問題ないと言っていることに注意してください。

4

2 に答える 2

8

スタックの巻き戻しと競合しなければ問題ありません。

オブジェクトを破棄してから、ポインターを介して再構築します。これは、デフォルトのコンストラクターを持たないオブジェクトの配列を構築および破棄する必要がある場合に行うことです。

問題は、これが例外的に安全でないことです。コンストラクターを呼び出すと例外がスローされ、スタックがアンワインドされ、デストラクタが 2 回目に呼び出された場合はどうなるでしょうか。

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

その側面は、特に未定義の動作になります。

于 2011-06-03T07:23:42.793 に答える
0

@sharptoothの答えは別として。もう2つのケースが気になります。少なくとも彼らは言及する価値があります。

(1)foo()を使用して割り当てられたヒープ上のポインタを使用してが呼び出された場合malloc()。コンストラクターは呼び出されません。安全ですか?

(2)派生クラスがを呼び出している場合はどうなりますかfoo()。それは良い行動になるでしょうか?例えば

struct Y : X {};  // especially when there is virtual ~X()
int main ()
{
  Y y;
  y.foo();
}
于 2011-06-03T08:03:41.723 に答える