2012-02-04 62 views
20

什么是错的这段代码,为什么会出现错误的答案:C++的构造函数:垃圾而常引用初始化

class X 
{ 
private: 
     const int a; 
     const int& b; 
public: 
     X(): a(10) , b(20) 
     { 
     //  std::cout << "constructor : a " << a << std::endl; 
     //  std::cout << "constructor : b " << b << std::endl; 
     } 

     void display() 
     { 
      std::cout << "display():a:" << a << std::endl; 
      std::cout << "display():b:" << b << std::endl; 

     } 
}; 


int 
main(void) 
{ 
     X x; 
     x.display(); 
return 0; 
} 

上面的代码给我结果作为

display():a:10 
display():b:1104441332 

但如果我删除默认的构造函数中的注释2线它给了我正确的结果是

constructor : a 10 
constructor : b 20 
display():a:10 
display():b:20 

请帮助,谢谢

回答

24

您正在初始化b作为参考临时

20已创建且仅存在于构造函数的作用域中。

之后的代码行为非常有趣 - 在我的机器上,我发现了不同的值,但基本行为仍然不确定。

这是因为当参考点超出范围时,它开始引用垃圾内存,从而导致不可预知的行为。

参见Does a const reference prolong the life of a temporary?;答案https://stackoverflow.com/a/2784304/383402链接到C++标准的相关部分,具体如下文字:

​​

这就是为什么你总是在构造函数中打印正确的价值,也很少后(但可能有时!) 。当构造函数退出时,参考悬空和所有投注都关闭。

+0

感谢您的回答。这解释了结果。但我可以知道如何初始化b? – 2012-02-04 07:16:02

+1

@VivekBasappa:让它引用一些变量,就像你打算的那样。或者,只需将它设置为“a”的值即可。 – 2012-02-04 07:18:01

+1

@VivekBasappa它是一个'int',所以你可能不希望它成为一个参考。 '鼻涕像复制一个'int'是昂贵的。 – Borealid 2012-02-04 07:18:44

4

b指的是临时的。在读取时(打印时),由于临时20在技术上已超出范围,因此读取的时间无效。

为了解释不一致的结果:

这是不确定的行为。你看到的可能是不同的,如果你:

  • 改变你的编译器
  • 改变编译器设置
  • 打造的另一种架构
  • 改变你的类的成员布局
  • 添加或删除的东西的x
  • 等实例近存储器区域

您应始终避免未定义的行为。

但为什么价值会改变?您的参考可能是指在打印时已被重写(例如重新使用)的堆栈地址。

+0

我真的无法理解最后的“为什么它是不同的......”部分。如果您能指出您正在谈论的内容,我将不胜感激。即使是第一个“至于为什么:”也不是那么清楚,尽管':'后面的内容确实有意义。 – batbrat 2012-02-04 07:06:32

+0

@batbrat扩展 – justin 2012-02-04 07:16:32

+1

+1好工作!现在它变得更有意义。 – batbrat 2012-02-04 08:03:16

3

您正在将const&绑定到一个临时表,它不会超出对构造函数的调用。 C++ 03标准特别指出:“在构造函数的ctor-initializer(12.6.2)中临时绑定到引用成员,直到构造函数退出”(12.2/5“Temporary objects”)。

因此,你的代码有未定义的行为 - 你可能会废话,或者似乎是'工作'的东西。

FWIW,MSVC 2010,该代码如下警告:

C:\temp\test.cpp(12) : warning C4413: 'X::b' : reference member is initialized to a temporary that doesn't persist after the constructor exits 
19

我会让我的编译器回答这个问题:

$ g++ -std=c++98 -Wall -Wextra -pedantic test.cpp 
test.cpp: In constructor 'X::X()': 
test.cpp:9:26: warning: a temporary bound to 'X::b' only persists until the constructor exits [-Wextra] 
$ 

你应该打开你的编译器的警告作为好。

+0

谢谢你的回答,你能解释一下为什么b是临时初始化吗?我想通过初始化列表初始化常量值 – 2012-02-04 07:11:39

+1

@VivekBasappa:'X :: b'是一个const引用,而不是一个常量值。 – 2012-02-04 07:16:46

+1

@VivekBasappa'const'不是问题,问题是它是一个没有参考的*引用*。 – 2012-02-04 07:21:07