2012-12-21 29 views
0

我用VC++ 2012運行下面的代碼:綁定右值,參考VC++的局部變量

#include <utility> 

struct A 
{ 
    int* m_p; 

    A() { m_p = new int; } 
    ~A() { delete m_p; } 

    A(const A& otherA) 
    { 
     m_p = new int; 

     // BOOM! 
     *m_p = *otherA.m_p; 
    } 
}; 

A&& CreateA() 
{ 
    A a; 
    return std::move(a); 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    A a2 = CreateA(); 
    return 0; 
} 

在創建A2 A的拷貝構造函數的調用 - 和崩潰,因爲在CreateA()中創建的源對象已被銷燬。 這是標準行爲嗎?這可能是一個編譯器錯誤?

請注意,如果將a2的類型從'A'更改爲'const A &',則不會發生崩潰 - 這增強了懷疑它確實是一個錯誤。 任何人都可以對此有所瞭解嗎?

注:我完全意識到這不是rvalue-refs的預期用法,並且此示例是人爲設計的。只是希望更好地掌握這種新型的行爲。

+4

引用是一個引用,不管它是R還是L.並且你不能引用不存在的東西... –

+0

可能的重複[可以請某人解釋移動語義給我?](http://stackoverflow.com/questions/3106110/can-someone-please-explain- move-semantics-to-me) – fredoverflow

回答

2

看看你的代碼會發生什麼:

  1. CreateA()
  2. 裏面的功能,一創建類型爲A的局部變量。
  3. 您創建一個右值引用指向這個局部變量
  4. 你回到這個右值引用
  5. 爲您退貨,A類型的對象,它的右值基準點,超出範圍,和被摧毀
  6. 參考現在指向一個銷燬的對象
  7. 你嘗試初始化a2爲對象的副本一旦函數調用
內部存在

而且這不起作用。你試圖複製的對象已經死了,不見了。未定義的行爲。

不要這樣做。 :)

在C++中,引用不會影響被引用對象的生存期。沒有「我指着這個東西,所以你不能摧毀它!」。

永不返回對本地對象的引用。它不起作用,所以...只是不這樣做。

+0

那麼,在C++中,肯定會引用* do *影響被引用對象的生命週期 - 如果它們是const :)。 閱讀關於左值引用的轉換語義(左值參考和值)我得到了 - 顯然是錯誤的 - 從CreateA返回的右值ref將被轉換爲值類型(因爲它被賦值爲值類型)的印象。好吧。謝謝。 –

+0

@OfekShilon:不,const引用會影響未命名臨時的生命週期。但不是一個已經超出範圍的本地對象。如果'a2'是一個const ref,*和*你的函數已經返回了'A'而不是'A &&',那麼它就會起作用。 :)你是對的,從'CreateA'返回的引用被轉換爲一個值類型,但是在引用所指向的對象被破壞之後發生,所以爲了做任何事情都爲時已晚;) – jalf

+0

這就是'在C++中,const引用影響被引用對象*的生命週期'的情況。正如你指出的那樣,這個對象是暫時的。 –

2

You cannot access a local variable outside its scope。右值引用不會改變:它們仍然是引用。呈現的代碼具有未定義的行爲,因爲它返回一個對局部變量的引用,然後訪問它。

不返回右值引用。絕大多數時候這是愚蠢的。返回值改爲:

A CreateA() 
{ 
    A a; 
    return a; // a move here is automatic 
       // unless you are using a compiler with outdated rules like MSVC 
    //return std::move(a); // ok, poor MSVC 
    // alternatively: 
    //return A{}; //or 
    //return A(); 
} 

當你寫A const& a2 = CreateA();沒有崩潰,因爲你實際上並沒有訪問任何對象。你所做的就是抓住一個懸而未決的參考。然而,這段代碼甚至沒有格式良好,只是恰好編譯,因爲MSVC有一些引用綁定的過期規則。

所以,基本上,這些行爲是編譯器錯誤和不確定的行爲:)的混合

+0

請注意,a2的類型是A - 它不是*引用。我希望我的代碼在語義上等價於你的代碼:首先應該調用一個副本,然後才能調用內部對象的dtor。這聽起來不正確嗎? –

+0

@OfekShilon返回類型是一個引用。它是對局部變量的引用。局部變量不會超出其範圍。 –

+0

而且我特意提出了一個先發制人的評論,說我完全意識到這不是rvalue參考的預期用法。沒必要指出這是愚蠢的。 –