2013-10-22 65 views
1

在我看來,能夠將r值引用轉換爲l值引用使得最終能夠以臨時值的形式訪問臨時值是沒有意義的。例如:從r值ref轉換爲l值ref,爲什麼它有效?

struct S 
{ 
    int val=5; 
}; 

void foo(S &&s) 
{ 
    S &s2=s; 

    s2.val=7 
} 

void foo2(S &s2) 
{ 
    s2.val=7 
} 

int main() 
{ 
    foo(S()); // This is fine 
    foo2(S()); // Error: Even though this is logically equivalent to foo() 
} 

foo()呼叫似乎是有效的在C++或至少它用gcc 4.7.1編譯。對foo2()的呼叫不是,即使這兩個功能似乎在邏輯上相同。是什麼賦予了?

+1

你沒有轉換任何東西。你將表達式's'的值綁定到引用變量's2'。沒有錯。 –

+0

[閱讀所有關於它](http://stackoverflow.com/a/5591006/2089675) – smac89

+1

你可以直接在'foo()'內執行's.val = 7'。所以'&'和'&&'沒有真正的區別,它們都可以以相同的方式使用。事實上,(設計上)很難說出它們之間的區別。最重要的區別是,當&&'是一個函數參數類型的一部分時,它允許它綁定(作爲參考)臨時。 –

回答

4

s已經是一個左值,就像任何其他命名變量一樣。所以有一個左值引用它並不會真的改變任何東西。

右值和左值之間的關鍵概念區別在於,您只能訪問一次右值,這樣可以安全地對它進行奇怪的操作。但是,如果這一個訪問將它綁定到一個右值引用,那麼您就創建了一種多次訪問它的方法,即將其轉換爲左值。所以你不能將它隱式地綁定到另一個右值引用,而你可以將它綁定到一個左值引用。

編輯:

這兩件東西邏輯上等同。在一箇中,你將一個右值綁定到一個左值引用。這是不允許的,因爲這是誤導。 (並不像允許一個左值綁定到右值引用那樣危險,但仍然有誤導)。通過取左值引用,foo2宣佈它可能會修改傳遞的對象,並且這絕對是函數操作的核心部分。將臨時函數傳遞給這樣的函數沒有任何意義,因爲您無法觀察修改。

另一方面,您將右值綁定到右值引用。 foo通過採用右值引用,宣佈它可能會修改傳遞的對象,但這是性能優化,並不意味着被任何人觀察到。傳遞一個臨時值是有道理的,但是傳遞一個非臨時值會是非常危險的,這就是爲什麼你必須在這種情況下明確表示std::move的論點。

然後,在foo中,將左值(恰好是指向右值引用類型的變量的表達式,但不相關)綁定到左值表達式。這是有道理的:你已經得到了你的右值引用變量s,它指向了一個由於已經傳遞給你的函數而成爲你的玩物的東西。因此,如果您想將其傳遞給修改其狀態的內容(例如foo2),然後觀察更改(您可以通過ss2這兩個選項),這在概念上完美無缺。

基本上,能夠被觀察一次或多次的東西是一個範圍問題。這就是爲什麼「相同」的東西(它不是真的一樣的東西,但你這樣想)可以綁定到一個上下文中的右值引用,並在另一個上下文中綁定左值引用。

+0

我更新了我的問題,以更具體地說明爲什麼我感到困惑。 –

+0

規則是非const的&不允許綁定到臨時對象。也許你在問「爲什麼用這個規則設計語言?爲什麼不允許非const&&綁定到臨時對象?」 –

+0

增加了更多細節。 –