2016-02-13 81 views
7
class Test { 

public: 

    int n1; 

}; 

Test func() { 

    return Test(); 

} 

int main() { 

    func() = Test(); 

} 

這對我沒有任何意義。如何以及爲什麼這是允許的?它是不確定的行爲?如果一個函數返回一個右值,那麼如何將右值設置爲另一個右值?如果我用任何原始類型嘗試這個,它會給我一個像我期望的錯誤。我知道左值是內存中的一個地方,函數也是創建一個臨時左值(右值?)並將其賦值給另一個左值?有人可以解釋這種語法的工作原理嗎將從函數返回的Rvalue賦值給另一個Rvalue

+0

「_IF函數返回一個rvalue_」事實並非如此。 – curiousguy

回答

6

函數調用表達式的值類別實際上是一個右值。

實際上,您不能在右值基元上調用複製賦值運算符。 C中rvalues的歷史定義實際上是它們可能不在assigment左側的區別。

雖然類的賦值操作符有點不同。他們是常規的成員職能。沒有規則阻止調用rvalues的成員函數。事實上,當功能有副作用時,它通常非常有用。

它是如何工作的,在臨時調用複製賦值運算符時,運算符複製右手參數,更改臨時狀態。在聲明之後,臨時對象被丟棄。沒有UB,只是毫無意義的複製。

可以通過聲明運算符使用像這樣的引用限定符來防止在右值上調用複製賦值:Test& operator=(Test) & = default;。 Ref-qualifiers僅在後面的C++ 11中添加,因此(隱式)複製分配不能被指定爲先前被ref-qualified定義。據推測,C++ 11並沒有改變隱式拷貝構造函數的限定符,以防止破壞舊的代碼賦予右值,儘管這樣的賦值似乎毫無意義。 High Integrity C++ Coding Standard建議您使用ref限定符和用戶定義的複製分配操作符。

+0

「_函數的返回值實際上是一個右值。」不,返回的對象是一個對象。 – curiousguy

+1

@curiousguy對象表達式具有值類別。在這種情況下,類別是r值。 – user2079303

+0

所有表達式都有類別,而不僅僅是指向對象的類別。返回的對象只是一個對象,而不是表達式。 – curiousguy

1

value categories而言(至少對我而言),學習曲線非常陡峭,但我相信你的例子中有terminology。所以

func() 

確實返回prvalue和C++標準看齊。 3.10.5(我只有當前draft,你的款號可能會有所不同),我們讀到:

爲對象的左值是必要的,以便修改的對象,除了類類型的右值可以也可用於在特定情況下修改其指稱對象。 [例如:調用 對象(9.3)的成員函數可以修改該對象。 - 結束示例]

因此,賦值運算符(它是成員函數,如標準中提到的示例)是規則的例外情況,允許修改rvalues。

這催生了在編程世界許多批評,其最極端的例子這C++ FQA摘錄:

(是的,糖衣死亡陷阱,你毫無頭緒啦啦隊。X& obj=a.b().c() - oops,b()是一個臨時對象,c()返回一個引用到它!不應該將其分配給參考。 。沒有多少機會的編譯器警告,要麼)

但在真正的C++編程有industrial applicationsnamed parameter成語:

std::cout << X::create().setA(10).setB('Z') << std::endl; 
+0

您得到的術語錯誤:函數調用'func()'是一個右值,返回值不是。 – curiousguy