2012-09-01 69 views
1

有人可以向我解釋爲什麼R值的輸出與L值不同?R值和L值的輸出不同。爲什麼?

#include <iostream> 
#include <vector> 
using namespace std; 

template<typename Ct> 
struct ct_wrapper { 
    Ct&& ct; // R or L ref 
    explicit ct_wrapper(Ct&& ct) 
     : ct(std::forward<Ct>(ct)) { std::cout << this->ct[1];}; 
}; 

int main() { 

    // L-val 
    vector<int> v{1,2,3}; 
    ct_wrapper<vector<int>&> lv(v); 
    cout << endl << lv.ct[0] << lv.ct[1] << lv.ct[2] << endl; 

    // R-val 
    ct_wrapper<vector<int>&&> rv(vector<int>{1,2,3}); 
    cout << endl << rv.ct[0] << rv.ct[1] << rv.ct[2] << endl; 
} 

輸出(同爲gcc48和clang32):

2 
123 
2 
003 

回答

這是我與約翰內斯·紹布聊天有點埋沒,所以我把它放在這裏。

當臨時向量初始化r-value-ref成員變量rv.ct時,由於存在特殊的異常,臨時生存期不會延長:[class.temporary] p5:「臨時綁定到構造函數的ctor-initializer中的引用成員(12.6.2)一直存在,直到構造函數退出。「

回答

7

因爲你的會員只是一個參考。在第二種情況下,在本地rv變量的定義完成後,它引用的對象已經死亡。所以在cout後面的訪問是未定義的行爲。

+1

+1(還有其他所有),但我仍然感到困惑。我認爲當臨時綁定到r值ref時,它的壽命延長到r值變量的壽命。沒有?我們還有'rv.ct'。 –

+1

@LeonidVolnitsky有一個特殊的例外(因爲否則編譯器不可能得到這個權利):[class.temporary] p5:「臨時綁定到構造函數的ctor-initializer中的引用成員(12.6.2)直到 構造函數退出。「 (我想說的是參考文獻不是一定要臨時的,而是要參考一個臨時的,但我沒有在標準中看到這種區別。) – hvd

+3

@ hvd right。實際上,這個區別並不在條款類當中。該條款涉及表達式直接具有該屬性的情況。 (如果標準中的文本顯示「創建臨時值...」,則右值直接攜帶該臨時屬性)。其他規則指的是臨時*對象*,而不是以這種方式標記的表達式,所以需要總是仔細閱讀封閉的上下文以知道是什麼意思(恕我直言,規範在這裏很差,它可以做得更清楚,見http: //www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1299)。 –

3

您的程序有未定義的行爲,因爲您正在訪問一個懸掛參考。臨時向量在其出現的完整表達式的末尾被銷燬,但您保留對其的引用。

2

在r值情況下,您將臨時綁定到引用。當你到達最後一個輸出語句時它已經消失。

相關問題