2016-11-18 96 views
2

有人可以幫助我理解爲什麼下面的代碼將導致警告R值將導致警告,而不使用std ::的移動

struct A 
{ 
    A() : _a(0) {} 

    const int& _a; 
}; 


int main() 
{ 
    A a; 
} 

與警告

warning: binding reference member '_a' to a temporary value [-Wdangling-field] 
     A() : _a(0) {} 

但是這個代碼,其中std::move用於初始化成員_a,並不:

struct A 
{ 
    A() : _a(std::move(0)) {} 

    const int& _a; 
}; 


int main() 
{ 
    A a; 
} 

是不是0std::move(0)這兩個r值?

+0

_a在哪裏指這裏? – Steephen

+9

'_a'是一個引用,在ex1中你將它綁定到一個臨時('0'),以後使用它是UB。在ex2中,你使用'std :: move'作爲轉換來對編譯器進行「撒謊」,它會使警告靜音,但稍後訪問它仍然是UB。 –

+0

'const&'在類中使用時不延長生命週期。它只適用於函數參數和函數返回。 – NathanOliver

回答

9

這是一個表達式:

0 

這是一個非常小的表情,真的。但這是一種表達。

一旦表達式被評估,它就會消失。它消失了。加入無形的合唱團。去見它的製造者。它成爲一個前表達。

確實將一個const引用綁定到一個臨時值可將臨時值的範圍擴展到封閉範圍的末尾。

但是在這種情況下,表達式的範圍是構造函數。當構造函數完成時,臨時值被破壞。

您的編譯器注意到表達式的const引用仍然繼續存在,但是作爲類成員。您的編譯器建議您使用類成員現在會導致未定義的行爲。你的編譯器想成爲你的朋友。您的編譯器不希望您編寫錯誤的代碼,因此您可以從編譯器中獲得一些免費且友好的建議。

在另一種情況下,您添加了一些稍微複雜的代碼。它仍然是未定義的行爲,但代碼現在已經足夠複雜,編譯器無法看到未定義的行爲結果。但它仍然是一個錯誤。

編譯器會在編譯器看到它們時嘗試警告您潛在的問題。不幸的是,編譯器每次都找不到所有可能的潛在問題。但是,很明顯,編譯器會讓你知道。

+2

投票給巨蟒 –

+0

絕對散文。 – erip

+0

你確定嗎?如果是這樣的話,就不可能有聰明的指針。 – Noidea

-1

它們的返回值不完全相同。 從cppreference.com

特別地,標準::舉動產生x值表達式,用於標識 其參數噸。它正好等於一個static_cast到右值 參考類型。

現在,看着rvalue引用,我們看到第二例子對象「0」可以長壽:

右邊的值可以被用來初始化一個右值參考,在這種情況下 的由右值標識的對象的生命週期將延長至參考範圍結束的 。

這樣的引用(右值引用)之後被分配給類成員_a,這是允許的,所以你沒有錯誤。

此外,對臨時變量的右值引用可用於移動構造函數,因此如果正在初始化的成員具有它,我看不到問題。然而,在C++中,你永遠不知道什麼時候未定義的行爲會突然襲擊你:)

+0

Cppreference解釋了它解釋壽命延長的地方。現在與你引用的句子聯繫起來。 – Cubbi

+0

@Cubby,對不起,現在鏈接了什麼?我應該鏈接什麼? – Noidea

+0

cppreference中的「擴展」一詞現在可點擊,並導致解釋問題的頁面。 – Cubbi