13

効果的な C++ では、初期化リスト内のデータ要素を宣言の順序でリストする必要があると言われています。さらに、この理由は、データ要素のデストラクタがコンストラクタの逆の順序で呼び出されるためであると言われています。

しかし、これがどのように問題になるのかわかりません...

4

6 に答える 6

25

次のことをよく考えてください。

class Class {
    Class( int var ) : var1( var ), var2(var1 ) {} // allright
    //Class( int var ) : var2( var ), var1(var2 ) {} // var1 will be left uninitialized

    int var1;
    int var2;
};

2番目の(コメントアウトされた)コンストラクターは問題ないように見えますが、実際var2には初期化されるだけです-var1最初に初期var2化され、その時点ではまだ初期化されていない状態で初期化されます。

メンバー変数がクラス宣言にリストされているのと同じ順序で初期化子をリストすると、そのようなエラーのリスクははるかに低くなります。

于 2011-03-01T10:25:59.013 に答える
10

メンバーが何らかの形で相互に依存するクラスのオブジェクトでもある場合、構築と破棄の順序が重要になる場合があります。

簡単な例を考えてみましょう:

class MyString {
public:
  size_t s_length;
  std::string s;
  MyString(const char *str) : s(str), s_length(s.length()) {}
};

この例の意図はs_length、格納された文字列の長さを member が保持することです。ただし、 は の前s_lengthに初期化されるため、これは機能しません。したがって、のコンストラクターが実行される前に呼び出します! ss.lengths

于 2011-03-01T10:31:50.687 に答える
7

たとえば、次のようなクラスがあるとします。

class X {
  int a,b;
  X(int i) : b(i),a(b) { } // Constructor
};

クラス X のコンストラクタは、最初に "b" を初期化するように見えますが、実際には宣言順に初期化されます。つまり、最初に「a」を初期化します。ただし、「a」はまだ初期化されていない「b」の値に初期化されるため、「a」はジャンク値を取得します。

于 2011-03-01T10:28:46.533 に答える
3

破壊は構築の逆であるため、要素は逆の順序で破壊されます。

2 つのメンバーがあるaとしbます。bに依存しますaが、a依存しませんb

構築するときは、最初に構築aし、構築できるものが存在するようになりましbた。a破壊するとき、最初に破壊すると、これが問題になる場合がありbます。しかし、最初に破壊bし、完全性を確保します。

これは典型的です。たとえば群論では、 の逆数fg~g~f(どこで~fは の逆数f)

服を着るときは、まず靴下を履き、次に靴を履きます。服を脱ぐときは、まず靴を脱ぎ、次に靴下を脱ぎます。

于 2011-03-01T11:01:31.177 に答える
2

また、メンバーのコンストラクターの 1 つが例外をスローした場合も問題になる可能性があります。次に、デストラクタの初期化リストに似たものがないため、既に適切に構築されたすべてのメンバーを何らかの順序で破棄する必要があります。この順序は、クラス宣言でのメンバーの出現の逆順です。例:

#include <iostream>

struct A1 {
  A1(int) { std::cout << "A1::A1(int)" << std::endl; }
  ~A1() { std::cout << "A1::~A1()" << std::endl; }
};

struct A2 {
  A2(int) { std::cout << "A2::A2(int)" << std::endl; }
  ~A2() { std::cout << "A2::~A2()" << std::endl; }
};

struct B {
  B(int) { std::cout << "B::B(int)" << std::endl; throw 1; }
  ~B() { std::cout << "B::~B()" << std::endl; }
};

struct C {
  C() : a1(1), a2(2), b(3) { std::cout << "C::C()" << std::endl; } // throw 1; }
  ~C() { std::cout << "C::~C()" << std::endl; }
  A1 a1;
  A2 a2;
  B b;
};

int main() {
  try {
    C c;
  } catch (int i) {
    std::cout << "Exception!\n";
  }
}

出力は次のようになります。

A1::A1(int)
A2::A2(int)
B::B(int)
A2::~A2()
A1::~A1()
Exception!
于 2011-03-01T10:42:56.677 に答える
1

さらに、この理由は、データ要素のデストラクタがコンストラクタの逆の順序で呼び出されるためであると言われています。

Class component order of initialisationでの Steve Jessop のコメントを参照してください。

于 2011-06-29T09:57:48.370 に答える