C ++以奇怪的方式处理未初始化的字段

时间:2017-01-24 17:30:52

标签: c++ visual-c++

下面的示例显示了以两种方式读取未初始化的字段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;
}

3 个答案:

答案 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

这说明了坚持良好惯例的重要性总是提供你自己的默认构造函数。编译器可能通过不向您的成员分配任何特定值来做正确的事情,因为您可以在下一个操作中分配另一个值。这可以节省一个操作。该成员将简单地分配在堆栈上,在这种情况下,该成员获得一个随机值。如果您在另一台计算机上运行此代码,您肯定会获得不同的值。