80

今日、いくつかのコードを書いていて、変なコンパイル エラーが発生しました。これは、宣言された順序とは異なる順序でメンバー変数を初期化したことが原因のようです。

例:

class Test {
    int a;
    int b;

public:
    Test() : b(1), a(2) {
    }
};

int main() {
    Test test;
    return 0;
}

次に、次のようにコンパイルすると-Werror -Wall:

$ g++ -Werror -Wall test.cpp
test.cpp: In constructor ‘Test::Test()’:
test.cpp:3:9: error: ‘Test::b’ will be initialized after [-Werror=reorder]
test.cpp:2:9: error:   ‘int Test::a’ [-Werror=reorder]
test.cpp:6:5: error:   when initialized here [-Werror=reorder]
cc1plus: all warnings being treated as errors

私はそれ-WallがGCCに過度の警告を出すように明示的に要求していることを理解していますが、それらすべてには理由があると思います. では、メンバー変数を初期化する順序はどのように重要なのでしょうか?

4

6 に答える 6

114

その理由は、コンストラクターで初期化する順序ではなく、クラスで宣言された順序で初期化され、コンストラクターの順序が使用されないことを警告しているためです。

bこれは、依存の初期化aまたはその逆のエラーを防ぐのに役立ちます。

この順序の理由は、デストラクタが 1 つしかなく、クラス メンバーを破棄するために「逆の順序」を選択する必要があるためです。この場合、最も簡単な解決策は、クラス内の宣言の順序を使用して、属性が常に正しい逆の順序で破棄されるようにすることでした。

于 2012-08-31T21:09:46.363 に答える
50

宣言されている順序でメンバー変数を初期化する必要があるのはなぜですか?

メンバー、必要かどうかに関係なく、宣言された順序で初期化されます。警告は、要求している順序が実際の初期化の実行順序と異なることを示しています。

于 2012-08-31T21:14:52.037 に答える
40

読みやすさが低下し、誤解を招く可能性があるため、使用しないでください。

あなたがした場合:

Test() : b(1), a(b) {}

bthenaは両方とも に設定されているように見えますが1、実際には の初期化されていない値がに初期化される前にb使用されます。ab1

于 2012-08-31T21:04:39.230 に答える
15

実際、コンパイラは、初期化子を別の順序で記述した場合でも、常に宣言の順序で変数を初期化します。したがって、初期化を宣言の順序で記述しないと、初期化子の順序が初期化の順序に適合しなくなり、初期化が相互に依存している場合に微妙なバグが発生する可能性があります。

たとえば、コードを考えてみましょう

Test(): b(42), a(b) {}

aの前に初期化されるため、これはバグですが、問題bないように見えます。宣言の順序 (初期化の順序) で記述すると、バグが明らかになります。

Test(): a(b), b(42) {}

バグはそれよりも微妙な場合があることに注意してください。たとえばa、 とbは、コンストラクターで何かを出力するクラス型です。次に、「間違った」順序を使用すると、bの出力が の前に表示されるべきであると考えられますaが、実際には逆になります。a最初に表示される の出力が無効なファイルにつながる場合、それもバグですが、コンストラクターが別の翻訳単位にある場合、コンパイラーが問題に気付く方法はありません (コンパイラーは並べ替えが正しいかどうかを認識できないという事実は別として)。バグではありません)。したがって、コンパイラが一致しない順序のすべてのインスタンスについて警告するだけであることは合理的です。

于 2012-08-31T21:08:53.800 に答える
5

-Wall が明示的に GCC に過剰な警告を出すように要求していることは理解していますが、それらすべてには理由があると思います。

-壁は始まりに過ぎません。名前が示すものとは反対に、-Wall はすべての警告を有効にするわけではありません。間違いなく「過剰」な警告がいくつかありますが、それらはまさに -Wall が有効にしない警告です。私はいつも -Wall とその他を使用しています。

あなたの苦情については、他の人がすでに指摘しているように、この警告には十分な理由があります。順序を指定したからといって、コンパイラがその順序を使用するわけではありません。コンパイラが標準に従って使用する必要がある順序は、クラス定義に基づいています。

于 2012-08-31T21:37:37.397 に答える