2012-02-02 69 views
17

今天早上我正在處理一些模板代碼,我使用了BOOST_STATIC_ASSERT來確保我沒有創建對錯誤類型的引用,因爲我認爲這可能是一個更清晰的錯誤消息。然而,當我試圖消除靜態斷言來看看我很震驚地發現,GCC甚至沒有抱怨當您嘗試做一個const雙&指爲int的替代編譯器錯誤:C++如何處理const double&引用int?

#include <iostream> 

int main() 
{ 
    int x = 5; 
    const double& y = x; 
    std::cout << y << std::endl; 

    return 0; 
} 

編譯,甚至沒有警告:

$ g++ ~/stuff/badRef.cpp -Wall -Wextra -pedantic 
$ a.out 
5 

這是怎麼回事?這是不確定的行爲?如果是的話爲什麼不gcc抱怨?在我的機器上,int是4個字節,double是8.這意味着當打印一個雙精度值時,它應該將該地址處的8個字節解釋爲double並打印出來,但實際上在那個位置上有一個4字節的int。

非常困惑。幫幫我!

+0

哪個版本的GCC? – 2012-02-02 23:13:54

+0

它是版本4.3.3。 – voltrevo 2012-02-02 23:32:50

+0

當你在'const double&y = x;'之後添加'x = 42;'時會發生什麼?一見鍾情可能會好奇/出乎意料。 – moala 2012-02-03 10:10:09

回答

22

const double& y = x;創建一個臨時值爲double的值爲static_cast<double>(x),然後將該臨時值綁定到y。臨時使用期限延長至y的使用期限。

這是完全合法的C++(03和11),因此缺少警告/錯誤。

+0

太棒了。我實際上在你回答之前通過查看當你增加x後會發生什麼,然後打印y來計算出它。它沒有改變,所以我認爲 - 「當然,它綁定到臨時!」。另外,gcc也會用-std = C++ 98來接受它,所以我猜它也是有效的C++ 98呢? – voltrevo 2012-02-02 23:31:02

+0

@ Mozza314:「*我猜它也是有效的C++ 98?」是的;我手邊沒有那個特定標準的副本,但我相當肯定這不是在C++ 03中添加的東西之一。不過請記住,'-std = C++ 98'實際上強制執行C++ 03規則,而不是C++ 98規則,參數名稱不被承受。 – ildjarn 2012-02-02 23:32:27

+0

我不明白...爲什麼你會在綁定到臨時而不是'const double'時執行'const double&'操作? – Mehrdad 2012-02-02 23:40:35

2

const T&可以綁定到一個臨時的,所以x正在轉換爲double和副本綁定到y。如果你檢查,你會看到&x != &y。這種行爲的原因是允許將文字傳遞給參數爲const的函數。

+0

好吧,不是「複製存儲」,「y」綁定到轉換產生的臨時數據,因爲它是一個常量左值引用。 – 2012-02-02 23:15:03

+0

@CatPlusPlus:如果不是澄清,那麼將「存儲在」中的「綁定到」替換爲至少在學術上是正確的。 :P – 2012-02-02 23:21:00

11

它是明確的和合法的。 y是指臨時的。也可以考慮當你傳遞參數:

void foo(const int& p); 
foo(3.14); 

還請注意,這不是有效的C++ 如果引用不是const的。 VS 6得到了錯誤,並允許綁定一個可變的引用臨時。這僅適用於常量引用。

1

對於那些認爲指針和引用相同的人來說,這是一個很好的例子。

double const*const y2 = &x; 

gives 
bad.cpp:7:30: error: cannot convert ‘int*’ to ‘const double* const’ in initialization 

它適用於參考的原因在其他文章中解釋。