2014-04-06 32 views
5

有一個類保持一個參考我希望下面的代碼失敗慘,但它編譯:爲什麼這個班舉行參考可複製?

#include <iostream> 

struct ReferenceHolder 
{ 
    std::string& str; 

    ReferenceHolder(std::string& str) 
    : str(str) 
    {} 
}; 

// Why does this compile? 
ReferenceHolder f() { 
    std::string str = "Hello"; 
    return ReferenceHolder(str); 
} 

int main() { 
    ReferenceHolder h = f(); 
    std::cout << "Should be garbage: " << h.str << '\n'; 
    return 0; 
} 

編譯器:克++ 4.7.2(與-std = C++ 11)

編輯:即使使用-fno-elide構造函數編譯也很愉快

+0

顯然它正在移動。如果你明確地刪除移動構造函數,它不會編譯。 – jrok

+0

@jrok的確如此,但據我所知,它既可複製又可移動。 – dyp

+0

有趣的是,根據研磨機CPU(安全講座)的介紹,在這個體系結構中,你會遇到分段錯誤。 –

回答

7

複製初始化類沒有問題,例如:新參考只是簡單地初始化爲指向與舊過程相同的對象。當然,當函數返回離開引用懸空時,你會得到未定義的行爲。

該引用可防止默認初始化和複製分配;所以下面的小改變會因爲以下原因而失敗:

ReferenceHolder h; // ERROR: can't default-initialise the reference 
h = f();   // ERROR: can't reassign the reference. 
1

此代碼具有未定義的行爲,請參見the classic answer from Eric Lippert

h的引用綁定到從f()在返回值的引用,它被綁定到ReferenceHolder在返回表達,所以h引用strf()從它的範圍之外。

+0

我知道。請參閱:「應該是垃圾」 –

+1

@DieterLücking:未定義的行爲並不意味着「垃圾」,它的意思是「任何東西」。 – Mankarse

+1

換句話說,默認的複製構造函數只是遞歸地複製成員(就像它總是這樣),而對於引用而言,這只是指引用原始數據。剩下的唯一要解決的問題就是您的期望,即代碼將慘敗,並且字符串將包含垃圾,當未定義的行爲不能保證這些事情。 – Mankarse