g++ -Wall 选项包括 -Wreorder。该选项的作用如下所述。我不清楚为什么有人会关心(特别是足以在 -Wall 中默认打开它)。
-Wreorder(仅限 C++) 当代码中给出的成员初始化器的顺序不正确时发出警告 匹配它们必须执行的顺序。例如: 结构 A { 诠释我; 诠释 j; A(): j (0), i (1) { } }; 编译器会将 i 和 j 的成员初始化器重新排列为 匹配成员的声明顺序,发出警告 影响。此警告由 -Wall 启用。
g++ -Wall 选项包括 -Wreorder。该选项的作用如下所述。我不清楚为什么有人会关心(特别是足以在 -Wall 中默认打开它)。
-Wreorder(仅限 C++) 当代码中给出的成员初始化器的顺序不正确时发出警告 匹配它们必须执行的顺序。例如: 结构 A { 诠释我; 诠释 j; A(): j (0), i (1) { } }; 编译器会将 i 和 j 的成员初始化器重新排列为 匹配成员的声明顺序,发出警告 影响。此警告由 -Wall 启用。
考虑:
struct A {
int i;
int j;
A() : j(0), i(j) { }
};
现在i
被初始化为某个未知值,而不是零。
或者, 的初始化i
可能会产生一些顺序很重要的副作用。例如
A(int n) : j(n++), i(n++) { }
问题是有人可能会在构造函数中看到成员初始化器列表,并认为它们是按该顺序执行的(首先是 j,然后是 i)。它们不是,它们按照成员在类中定义的顺序执行。
假设你写了A(): j(0), i(j) {}
. 有人可能会读到它,并认为 i 以值 0 结束。它没有,因为你用 j 初始化它,它包含垃圾,因为它本身没有被初始化。
警告提醒你写A(): i(j), j(0) {}
,希望看起来更可疑。
其他答案提供了一些很好的例子来证明警告选项是合理的。我想我会提供一些历史背景。C++ 的创建者 Bjarne Stroustrup 在他的《C++ 编程语言》(第 3 版,第 259 页)一书中解释道:
在执行包含类自己的构造函数的主体之前调用成员的构造函数。构造函数的调用顺序是它们在类中的声明顺序,而不是它们在初始化列表中出现的顺序。为避免混淆,最好按声明顺序指定初始化程序。成员析构函数的调用顺序与构造的相反。
如果您的初始化程序有副作用,这可能会咬您一口。考虑:
int foo() {
puts("foo");
return 1;
}
int bar() {
puts("bar");
return 2;
}
struct baz {
int x, y;
baz() : y(foo()), x(bar()) {}
};
上面将打印“bar”然后是“foo”,尽管直觉上会假设 order 是写在初始化列表中的。
或者,如果x
和y
是具有构造函数的用户定义类型,则该构造函数也可能具有副作用,具有相同的非显而易见的结果。
当一个成员的初始化程序引用另一个成员时,它也可以表现出来。
存在警告是因为如果您只是阅读构造函数,它看起来就像j
在i
. 如果一个用于初始化另一个,这将成为一个问题,如
struct A {
int i;
int j;
A(): j (0), i (this->j) { }
};
当您只查看构造函数时,这看起来很安全。但实际上,j
在用于初始化的地方还没有初始化i
,所以代码不会按预期工作。因此发出警告。