2012-02-04 80 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