c++ - 为什么要按照声明成员变量的顺序初始化成员变量?

我今天编写了一些代码,得到一个奇怪的编译错误,是由于初始化成员变量的顺序与声明的成员变量的顺序不同而引起的。

例如:


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

时间:

原因是,因为它们是按照在类中声明的顺序进行初始化的,而不是您在构造函数中对其进行初始化,警告构造函数的排序将不会被使用。

为什么应按成员变量的声明顺序初始化它们?

无论您是否想要,成员都将按照声明的顺序进行初始化。警告是告诉您要求的顺序与初始化的实际执行顺序不同。

如果你这样做:


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

ba都设置为1,而实际上b的未初始化值用于初始化。

实际上编译器总是初始化变量声明的顺序,即使你写的初始化顺序不同。 因此如果你不写声明的顺序初始化,初始化的顺序不符合的顺序初始化,这可能导致微妙 Bug initialisations彼此依赖。

例如考虑代码


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

这是一个 Bug 因为 ab 之前初始化,但它看起来 ok。 如果按照声明( 这是初始化的顺序)的顺序写入,Bug 将变得明显:


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

注意 Bug 也可以比这更微妙的,例如想象 ab 类类型输出的东西在他们的构造函数;然后"不正确"订单你已经认为 ba 当之前的输出应该出现在现实中会发生逆转。 如果 a 输出出现第一次将导致一个无效的文件,这也是 Bug, 但没有办法编译器能够注意这个问题在另一个翻译单元( 编译器无法知道是否重新排序或者不是 Bug的事实) 如果构造函数。 因此编译器只警告non-matching订单的每个实例是合理的。

我意识到-Wall明确要求GCC带警告去 over-the-top,但我假设他们都有一个原因。

-Wall只是一个开始。 名称所暗示的相反,-Wall不启用所有警告。 有一些警告是"上方上方"的警告,但这些警告恰恰是-Wall没有启用的警告。 我总是用-Wall加上其他的。

至于你的投诉,就像其他人已经注意到的,这个警告有一个很好的理由。 仅仅因为你指定了一个顺序并不意味着编译器会使用那个顺序。 编译器必须按照标准使用的顺序基于类定义。

...