g ++ -Wall选项包括-Wreorder。该选项的作用如下所述。我不明白为什么有人会关心(特别是在-Wall中默认打开它)。
-Wreorder (C++ only) Warn when the order of member initializers given in the code does not match the order in which they must be executed. For instance: struct A { int i; int j; A(): j (0), i (1) { } }; The compiler will rearrange the member initializers for i and j to match the declaration order of the members, emit-ting a warning to that effect. This warning is enabled by -Wall.
答案 0 :(得分:227)
考虑:
struct A {
int i;
int j;
A() : j(0), i(j) { }
};
现在i
被初始化为某个未知值,而不是零。
或者,i
的初始化可能会产生一些副作用,顺序很重要。 E.g。
A(int n) : j(n++), i(n++) { }
答案 1 :(得分:35)
问题是有人可能会在构造函数中看到成员初始化者的列表,并认为它们是按照该顺序执行的(先是j,然后是i)。它们不是,它们按照成员在班级中定义的顺序执行。
假设你写了A(): j(0), i(j) {}
。有人可能会读到这一点,并认为我最终得到的值为0.它没有,因为你用j初始化它,它包含垃圾,因为它本身没有被初始化。
警告提醒你写A(): i(j), j(0) {}
,希望看起来更可疑。
答案 2 :(得分:14)
其他答案提供了一些很好的例子来证明警告选项的合理性。我以为我会提供一些历史背景。 C ++的创建者Bjarne Stroustrup在他的书The C++ programming language(第3版,第259页)中解释道:
在执行包含类的自身构造函数的主体之前调用成员的构造函数。构造函数按它们在类中声明的顺序调用,而不是它们在初始化列表中出现的顺序。为避免混淆,最好按声明顺序指定初始值设定项。成员析构函数以相反的构造顺序调用。
答案 3 :(得分:9)
如果你的初始化者有副作用,这可能会咬你。考虑:
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
是一些带有构造函数的用户定义类型,那么该构造函数也可能有副作用,但结果不明显。
当一个成员的初始化程序引用另一个成员时,它也可以表现出来。
答案 4 :(得分:6)
警告存在是因为如果您只是阅读构造函数,则j
之前的i
似乎已初始化。如果用于初始化另一个,则会成为问题,如
struct A {
int i;
int j;
A(): j (0), i (this->j) { }
};
当您查看构造函数时,此看起来是安全的。但实际上,j
尚未在用于初始化i
的位置进行初始化,因此代码将无法按预期工作。因此警告。