web-dev-qa-db-ja.com

g ++ -Wreorderのポイントは何ですか?

G ++ -Wallオプションには-Wreorderが含まれます。このオプションの機能については、以下で説明します。なぜ誰かが気にするのか私には明らかではありません(特に-Wallでデフォルトでこれを有効にするのに十分です)。

-Wreorder(C++のみ)
コードで指定されたメンバー初期化子の順序が実行する必要のある順序と一致しない場合に警告します
。例えば:
 
 struct A {
 int i; 
 int j; 
 A():j(0)、i(1) {} 
}; 
 
コンパイラは、iおよびjのメンバー初期化子を
のメンバーの宣言順序に一致するように再配置し、警告を発行します。その
効果。この警告は-Wallによって有効になります。
135
Peeter Joot

考慮してください:

struct A {
    int i;
    int j;
    A() : j(0), i(j) { }
};

iはゼロではなく、未知の値に初期化されます。

または、iの初期化には、順序が重要な副作用が発生する場合があります。例えば。

A(int n) : j(n++), i(n++) { }
232
int3

問題は、誰かがコンストラクターでメンバー初期化子のリストを見て、それらがその順序で実行されると考えるかもしれないことです(jが最初、次にi)。そうではなく、メンバーがクラスで定義されている順序で実行されます。

A(): j(0), i(j) {}と書いたとします。誰かがそれを読んで、iが値0で終わると思うかもしれません。jで初期化したので、そうではありません。

警告はA(): i(j), j(0) {}を書くことを思い出させます。

36
Steve Jessop

他の答えは、警告のオプションを正当化するいくつかの良い例を提供しました。歴史的な背景を提供すると思いました。 C++の作成者であるBjarne Stroustrupは、彼の本で説明しています C++プログラミング言語 (第3版、259ページ):

メンバーのコンストラクターは、それを含むクラスのコンストラクターの本体が実行される前に呼び出されます。コンストラクターは、初期化子リストに表示される順序ではなく、クラスで宣言された順序で呼び出されます。混乱を避けるため、宣言順に初期化子を指定するのが最善です。メンバーデストラクターは、構築の逆の順序で呼び出されます。

14
gkb0986

イニシャライザに副作用がある場合、これは噛みつきます。考慮してください:

int foo() {
    puts("foo");
    return 1;
}

int bar() {
    puts("bar");
    return 2;
}

struct baz {
    int x, y;
    baz() : y(foo()), x(bar()) {}
};

上記は「bar」、次に「foo」を出力しますが、たとえ直観的には順序は初期化リストに書かれていると仮定します。

あるいは、xおよびyがコンストラクターを使用するユーザー定義型である場合、そのコンストラクターにも副作用があり、同じ非自明な結果が得られる場合があります。

また、あるメンバーのイニシャライザーが別のメンバーを参照するときにも現れます。

9
Pavel Minaev

警告が存在するのは、コンストラクタを読み取った場合、jiの前に初期化されているように見えるためです。一方が他方を初期化するために使用される場合、これは問題になります

struct A {
  int i;
  int j;
  A(): j (0), i (this->j) { }
};

コンストラクターを見ると、これはlooks safeです。しかし、実際には、jiの初期化に使用される時点ではまだ初期化されていないため、コードは期待どおりに機能しません。したがって、警告。

7
jalf