我在写一些代码,今天得到了一个奇怪的编译错误,这似乎是由不同的顺序比他们被宣布初始化成员变量引起的。
例:
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去过度的顶部有警告,但我相信有他们所有的原因。 因此,初始化成员变量的顺序怎么会事?
究其原因是因为他们在他们在你的类中声明的顺序进行初始化,而不是为了你在构造函数初始化它们,它的警告你,你的构造函数的订单将不会被使用。
这是为了帮助防止出现错误,其中的初始化b
依赖于a
或反之亦然。
这样做的原因排序是因为只有一个析构函数,它有挑一“逆序”破坏类成员。 在这种情况下,最简单的解决方案是使用类中声明的顺序,以确保属性被以正确的顺序相反总是破坏。
我为什么要初始化他们在声明的顺序成员变量?
成员将在他们的声明相同的顺序进行初始化,您是否希望与否。 该警告是告诉你的顺序你所要求的从初始化执行的实际顺序不同。
你不应该,因为它降低了可读性,可能引起误解。
如果你这样做:
Test() : b(1), a(b) {}
这样看来, b
然后a
都设定到1
,而实际上的未初始化的值b
被用来初始化a
前b
被初始化为1
。
实际上,编译器总是初始化中声明的顺序变量,即使你写在一个不同的顺序初始化。 因此,如果你不写初始化中声明的顺序,你的初始化的顺序不适合初始化的顺序,这可能会导致微妙的错误如果initialisations互相依赖。
例如,考虑代码
Test(): b(42), a(b) {}
这是因为一个bug a
之前初始化b
,但它看起来 OK。 如果您在声明的顺序(这是初始化的顺序)写出来,错误得到明显:
Test(): a(b), b(42) {}
请注意,错误也可以比微妙的; 例如想象a
和b
是类类型,其输出的东西在他们的构造函数; 然后用“不正确”为了你会认为b
的输出应该出现前a
S'时,现实中的反向不会发生。 如果a
首先出现的输出会导致一个无效的文件,这也是一个错误,但也没有办法,如果构造函数是在另一种译法单元(除了一个事实,即编译器无法知道,如果重新排序是编译器可能注意到这个问题或者是不是一个错误)。 因此,它是合理的,编译器只是警告不匹配的订单大约每个实例。
我认识到,-Wall明确要求GCC去过度的顶部有警告,但我相信有他们所有的原因。
-Wall仅仅是一个开始。 相反的是顾名思义,-Wall并不启用所有警告。 有一些警告,可以说是“洁癖”,但这些恰恰是-Wall不启用警告。 我总是用-Wall加上其他人。
至于您的投诉,正如其他人已经指出的那样,有一个很好的理由此警告。 仅仅因为你指定的顺序并不意味着编译器将使用该命令。 编译器必须按标准使用的顺序是基于类的定义。