web-dev-qa-db-ja.com

デストラクタができるのに、コンストラクタを明示的に呼び出せないのはなぜですか?

次のC++コードでは、デストラクタを明示的に呼び出すことはできますが、コンストラクタを呼び出すことはできません。何故ですか?明示的なctorがより多くの表現力のあるnifiedをdtorケースで呼び出しませんか?

class X { };

int main() {
  X* x = (X*)::operator new(sizeof(X));
  new (x) X;  // option #1: OK
  x->X();     // option #2: ERROR

  x->~X();
  ::operator delete(x);
}
28
Daniel Langr

コンストラクタが開始される前は、そのアドレスにはタイプXのオブジェクトがないためです。したがって、xXタイプとして逆参照するか、そのメンバー/メソッドにアクセスすると、未定義の動作になります。

したがって、x->X();(架空の構文)とx->~X()の主な違いは、2番目のケースでは、デストラクタなどの(特別な)メンバーを呼び出すことができるオブジェクトがあることです。最初のケースでは、まだオブジェクトはありませんでメソッドを呼び出すことができます(特別なメソッド-コンストラクターでも)。

このルールに例外がある可能性があると主張することもできますが、最終的には両方のケースで不整合がある構文優先の問題になります。現在の構文では、コンストラクターの呼び出しはコンストラクターの呼び出しのようには見えません。提案された構文では、デストラクターの呼び出しと対称性がありますが、オブジェクトのメソッドを逆参照/アクセスできるタイミングを制御するルールに矛盾があります。実際には、まだオブジェクトではない何かに対してメソッドを呼び出すことを許可する例外がなければなりません。次に、標準の文字で厳密に定義する必要がありますまだオブジェクトではないもの

37
bolov

これは鶏と卵の問題のバリエーションです。

オブジェクトのインスタンスが既に存在しているため、デストラクタをメンバー関数のように明示的に呼び出すことができます。

これを呼び出すインスタンスは存在し、コンストラクターによって完全に初期化される必要があるため、コンストラクターに対して同じことを行うことはできません。

これに対する唯一の例外は、オブジェクトにメモリを割り当てたが、インスタンスをまだ初期化していない場合です(つまり、インスタンスのメモリはありますが、初期化されていないため、実際のインスタンスになりません)。したがって、コンストラクタを呼び出す必要があります。これは、配置new、「オプション1」コメントの下に表示する構文が役立つ状況です。ただし、呼び出しを行う前はインスタンスを使用できないため、これはインスタンスで実行するメンバー呼び出しではありません。

9
dasblinkenlight