1. 程式人生 > >C++11 的右值引用(Rvalue reference)——細微卻最重要的改動

C++11 的右值引用(Rvalue reference)——細微卻最重要的改動


@王潛升 提到棧區物件的問題,只是右值引用解決的問題之一。更全面一些的話,可以說右值引用解決的是各種情形下物件的資源所有權轉移的問題。

第一次碼長文,程式碼都是臨時手敲,如有錯誤歡迎拍磚。

=====

C++11之前,移動語義的缺失是C++最令人詬病的問題之一。舉個栗子:

問題一:如何將大象放入冰箱?
這個答案是眾所周知的。首先你需要有一臺特殊的冰箱,這臺冰箱是為了裝下大象而製造的。你開啟冰箱門,將大象放入冰箱,然後關上冰箱門。

問題二:如何將大象從一臺冰箱轉移到另一臺冰箱?
普通解答:開啟冰箱門,取出大象,關上冰箱門,開啟另一臺冰箱門,放進大象,關上冰箱門。
2B解答:在第二個冰箱中啟動量子複製系統,克隆一隻完全相同的大象,然後啟動高能鐳射將第一個冰箱內的大象氣化消失。

等等,這個2B解答聽起來很耳熟,這不就是C++中要移動一個物件時所做的事情嗎?

“移動”,這是一個三歲小孩都明白的概念。將大象(資源)從一臺冰箱(物件)移動到另一臺冰箱,這個行為是如此自然,沒有任何人會採用先複製大象,再銷燬大象這樣匪夷所思的方法。C++通過拷貝建構函式和拷貝賦值操作符為類設計了拷貝/複製的概念,但為了實現對資源的移動操作,呼叫者必須使用先複製、再析構的方式。否則,就需要自己實現移動資源的介面。

為了實現移動語義,首先需要解決的問題是,如何標識物件的資源是可以被移動的呢?這種機制必須以一種最低開銷的方式實現,並且對所有的類都有效。C++的設計者們注意到,大多數情況下,右值所包含的物件都是可以
安全的被移動的。

右值(相對應的還有左值)是從C語言設計時就有的概念,但因為其如此基礎,也是一個最常被忽略的概念。不嚴格的來說,左值對應變數的儲存位置,而右值對應變數的值本身。C++中右值可以被賦值給左值或者繫結到引用。類的右值是一個臨時物件,如果沒有被繫結到引用,在表示式結束時就會被廢棄。於是我們可以在右值被廢棄之前,移走它的資源進行廢物利用,從而避免無意義的複製。被移走資源的右值在廢棄時已經成為空殼,析構的開銷也會降低。

右值中的資料可以被安全移走這一特性使得右值被用來表達移動語義。以同類型的右值構造物件時,需要以引用形式傳入引數。右值引用顧名思義專門用來引用右值,左值引用和右值引用可以被分別過載,這樣確保左值和右值分別呼叫到拷貝和移動的兩種語義實現。對於左值,如果我們明確放棄對其資源的所有權,則可以通過std::move()來將其轉為右值引用。std::move()實際上是static_cast<T&&>()的簡單封裝。


右值引用至少可以解決以下場景中的移動語義缺失問題: