下面的示例显示了以两种方式读取未初始化的字段a.i1。第一个调用不编译。但是,调用不执行任何操作的a.donothing(),原始调用编译正常并打印默认值0.为什么这种不一致?
我正在使用Visual Studio Community 2015,编译器输出如下:
Severity Code Description Project File Line Suppression State
Error C4700 uninitialized local variable 'a' used
class A {
public:
int i1;
void donothing() {}
};
int main() {
A a;
cout << "main1: " << a.i1 << endl; // compile fails
a.donothing();
cout << "main2: " << a.i1 << endl; // prints 0 (default)
return 0;
}
答案 0 :(得分:0)
编译器正在做它应该做的事情。您可以像这样修复它(作为许多解决方案中的一个解决方案):
class A {
public:
A(int i = 0) : i1(i) {}
int i1;
void donothing() {}
};
答案 1 :(得分:0)
在这两种情况下,最多都必须发出警告。调用donothing
取消错误的事实清楚地表明这是一个错误。您可以在Microsoft Connect报告。
此问题的一个简单解决方法是将声明更改为A a{};
。
您可以在Compiler Explorer的不同编译器上测试代码。
[编辑] 如果安全开发生命周期已开启(C4700
),则会将警告消息/sdl
视为错误。
答案 2 :(得分:-1)
取决于编译器,编译器应该提供一个默认构造函数,它将使用默认值初始化您的成员。但这种行为是不可靠的。从C ++ 11开始,你可以说ClassName()= default;最佳实践是证明您自己的默认构造函数。
您的代码从未在g ++ 5.4.0中出现任何编译器错误
#include <iostream>
using namespace std;
class A {
public:
//A() : i1(0) { } // compiler will provide this if you don't write anything
// since C++ 11 you can also say A() = default;
A() = default;
int i1;
void donothing() {}
void writeMember() const { cout << "i1 value: " << i1 << endl; }
};
// better provide a signature for the main function
int main(int argc, char* argv[]) {
A a;
a.writeMember();
cout << "main1: " << a.i1 << endl; // compile fails
a.donothing();
cout << "main2: " << a.i1 << endl; // prints 0 (default)
return 0;
}
编译存储在testclass.cpp
中的上述代码g++ -std=c++11 -o testclass testclass.cpp
通过使用C ++ 11默认,我得到了
i1 value: 4196976
main1: 4196976
main2: 4196976
如果你注释掉A()= default;这将依赖于编译器提供的初始化程序,或者编译器可能是懒惰的,并且由于性能原因没有做任何事情。你得到了
i1 value: 4196944
main1: 4196944
main2: 4196944
如果您在公开后取消注释该行:您应始终获得0
这说明了坚持良好惯例的重要性总是提供你自己的默认构造函数。编译器可能通过不向您的成员分配任何特定值来做正确的事情,因为您可以在下一个操作中分配另一个值。这可以节省一个操作。该成员将简单地分配在堆栈上,在这种情况下,该成员获得一个随机值。如果您在另一台计算机上运行此代码,您肯定会获得不同的值。