“右值引用”是什么?我賭兩個幣,沒人能講得比我清楚!不看絕對虧!

變量、左值、右值
C/C++ 中的變量 int a = 42;
a 為具名變量,該變量為 int 類型,類型 int 是該變量的屬性。42 是變量的內容(值),而且該值的類型要和該變量的類型一致。
動態(tài)類型語言如 JavaScript 中的變量 let a = 42;
a 為具名變量,但 a 沒有類型屬性,a 中的內容 42 具有類型 Number。
C/C++ 中 char c = a; [右值語義]
這里是將 a 的內容(值)取出來,轉換成 char 的值,存到 c 中。
而 a = 123; [左值語義]
是將 123 轉換成 int 的值,存到 a 中。
所以,當提到變量 a 時,就有兩個語義,表示變量盒子(具有地址、類型屬性)的左值語義,以及表示變量內容(所存值)的右值語義。
對以上概念的擴充。
字面量 42 是一個純右值 prvalue,沒有變量盒子的屬性(不具有地址)。
void func() 函數(shù),該函數(shù)名 func 是一個左值(具有地址)。對該函數(shù)的調用 func() 是一個 void 類型的表達式,是右值。
傳統(tǒng)的 swap 慣用法避免復制開銷
string temp;
// 對 temp 的計算與構建
// 實際返回的對象
string ret;
// 對于 STL 容器,swap 是一個開銷小且有 no-except 保證的操作
ret.swap(temp);
return ret;
}
注:對于以上函數(shù)的調用 string s = create_string(),在返回階段(按值返回)也有一次拷貝初始化,用 create_string() 中的返回值 ret 拷貝構造出調用者中的 s。根據(jù)編譯優(yōu)化的不同 (RVO),這個過程可能有一個中間臨時對象的拷貝構造,也可能一次拷貝構造都沒有,即調用者中的 s 被約束到 create_string() 中的 ret。
右值引用、移動語義 move semantic
需求和引出:上例中,在已知 temp 在 create_string() 返回后會消耗(即失效值 xvalue)情況下,如何在返回時,將 temp 內部管理的字符串資源偷取出來 (steal),放到另一個 string 對象的內部(并接受這個新對象的管理),比如調用者的 s 中,這樣就避免了字符串資源拷貝。
string ret = std::move(temp);
move() 本質上是一個到 T&& 右值引用的類型轉換,本例中即 ret = (string&&) temp
根據(jù) string 構造函數(shù) 和 賦值操作 的參數(shù),調用其 copy 版(如果參數(shù)是左值引用),或 move 版(如果參數(shù)是右值引用)
給 string 編寫 move ctor/assignment 稱為將 string 變?yōu)?move-aware
本例中 move 操作完成后,原先 temp 就失效了(不可用)