コンストラクターでの初期化順序

それで、ここに小さなC ++プログラムがあります:



 #include <iostream>

クラスA {
プライベート:
   int a;
   int b;
公開:
   A(int x):b(x)、a(b){}
   void dump(){
     std :: cout << "a =" << a << "b =" << b << std :: endl;
   }
 };

 int main(){
   A a(42);
   a.dump();
   0を返します。
 }


彼女が配ると思うなら



 a = 42 b = 42




その後、あなたはだまされ、それは次のようなものを与えるでしょう



 a = 4379 b = 42


これは、コンパイラが変数を行にリストされている間違った順序で初期化するために発生します



  A(int x):b(x)、a(b) 


最初に変数「a」が初期化され、次に変数「b」が初期化されます。 「a」の初期化時には、変数「b」の値は不定のままであるため、「a」も不定値を受け取ります。



「a」と「b」が単なる整数ではなく、たとえば、コンストラクターパラメーターが割り当てられたメモリの量を決定する複雑なオブジェクトであると想像すると、状況はさらに劇的になります。 その後、熊手は額に非常に強く当たることがあります。



また、初期化はどの順序で行われますか?



実際、初期化の順序は行の順序に依存しません



  A(int x):b(x)、a(b) 


すべては宣言の順序によって決定されます。



   int a;
   int b;


これらの2行を適切に再配置すると、初期化の順序が変更され、コンストラクターが正しく機能します。



これを確認するには、この例を試してください



 #include <iostream>

クラスS {
プライベート:
   intデータ;
公開:
   S(int x){
     std :: cout << "S(int x)x =" << x << std :: endl;
    データ= x;
   }
   S(S&x){
     std :: cout << "S(S&x)x.data =" << x.data << std :: endl;
     data = x.data;
   }
   int dump(){
    戻りデータ。
   }
   〜S(){
     std :: cout << "〜S()x.data =" << this-> data << std :: endl;
   }
 };

クラスA {
プライベート:
   S a;  //交換してみます
   S b;  //これら2つの宣言
公開:
   A(int x):b(x)、a(b){}
   void dump(){
     std :: cout << "a =" << a.dump()<< "b =" << b.dump()<< std :: endl;
   }
 };

 int main(){
   A a(1);
   a.dump();
   0を返します。
 }


しかし、私はこの結果を得ました:



 S(S&x)x.data = 134515845
 S(int x)x = 1
 a = 134515845 b = 1
 〜S()x.data = 1
 〜S()x.data = 134515845


コンストラクター「S(S&x)」が最初に実行されたことに注意してください。 宣言を再配置すると、すべてが正常に機能します。



これは何ですか C ++のバグ?



もちろん違います!



実際には、オブジェクトが削除されると、すべての破壊的なアクションは、構築順序とまったく逆の順序で実行される必要があります。 ただし、C ++では、いくつかのコンストラクターを共存させることができます。 異なるコンストラクターの初期化順序が異なる場合、オブジェクトの一部を破棄する順序は? オブジェクトがどのように作成されたかを覚えておくと、非常にコストがかかります。 残っていることが1つだけあります。すべての設計者に、コードに関係しない厳密な初期化順序を導入することです。



それが行われました。



また、このレーキを誤って踏まないように、常にクラスメンバーが宣言されているのと同じ順序で初期化を記述することをお勧めします。



すべて成功!



upd:このhere節12.6.2#5ページ197に標準があります。

upd2:またはhttp://www.kuzbass.ru:8086/docs/isocpp/special.html#class.base.init(EntropiouSに感謝)




All Articles