问题描述
在此示例中,我有两个类:Test和Test2。他们的两个构造函数都错误地从自身初始化成员变量“ val_”,而不是从预期的参数“ val”初始化成员变量。区别在于Test使用{}语法初始化,而Test2使用()语法初始化。仅Test2的初始化会生成“已自身初始化”警告。
我正在使用-Wall进行编译,这意味着-Winit-from-self。从打印结果可以看出,两个构造函数都为_val打印了错误的值。
909> cat initSelfTest.cc
#include <iostream>
using namespace std;
class Test {
public:
Test (int val);
private:
int val_;
};
Test::Test (int val)
: val_ {val_}
{
cerr << "Test::Test; val = " << val << "; val_ = " << val_ << "\n";
}
class Test2 {
public:
Test2 (int val);
private:
int val_;
};
Test2::Test2 (int val)
: val_ (val_)
{
cerr << "Test2::Test2; val = " << val << "; val_ = " << val_ << "\n";
}
int main (int argc,char **argv) {
Test test {781981};
Test2 test2 {781981};
}
910> gcc --version
gcc (GCC) 8.2.0
Copyright (C) 2018 Free Software Foundation,Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
911> g++ -Wall -o initSelfTest initSelfTest.cc
initSelfTest.cc: In constructor ‘Test2::Test2(int)’:
initSelfTest.cc:23:1: warning: ‘Test2::val_’ is initialized with itself [-Winit-self]
Test2::Test2 (int val)
^~~~~
initSelfTest.cc: In constructor ‘Test::Test(int)’:
initSelfTest.cc:12:13: warning: ‘*<unknown>.Test::val_’ is used uninitialized in this function [-Wuninitialized]
: val_ {val_}
^~~~
initSelfTest.cc: In constructor ‘Test2::Test2(int)’:
initSelfTest.cc:24:13: warning: ‘*<unknown>.Test2::val_’ is used uninitialized in this function [-Wuninitialized]
: val_ (val_)
^~~~
912> ./initSelfTest
Test::Test; val = 781981; val_ = 0
Test2::Test2; val = 781981; val_ = 0
913>
解决方法
您正在使用该值进行初始化之前,这是未定义的行为,不需要/保证没有错误消息。通常,标准不要求警告。
对于“为什么UB不是错误?”我只能推测。考虑到有些情况看起来非常相似,但是完全可以。例如
struct foo {
foo& f;
};
foo f{f};
仅取消引用会导致问题,但是可以存储引用以供以后使用。我可以想象,除了邪恶的情况之外,编译器通常无法分辨出这种有效的情况。