右值

rvalue 表示式是可以隱式移出的任何表示式,無論它是否具有標識。

更準確地說,rvalue 表示式可以用作函式的引數,該函式接受 T && 型別的引數(其中 Texpr 的型別)。只有 rvalue 表示式可以作為這些函式引數的引數給出; 如果使用非右值表示式,則過載決策將選擇不使用右值引用引數的任何函式。如果不存在,則會出現錯誤。

rvalue 表示式的類別包括所有 xvalue 和 prvalue 表示式,並且只包含那些表示式。

標準庫函式 std::move 用於將非右值表示式顯式轉換為右值。更具體地說,它將表示式轉換為 xvalue,因為即使它之前是無標識的 prvalue 表示式,通過將其作為引數傳遞給 std::move,它獲得了 identity(函式的引數名稱)並變為 xvalue。

考慮以下:

std::string str("init");                       //1
std::string test1(str);                        //2
std::string test2(std::move(str));             //3

str = std::string("new value");                //4 
std::string &&str_ref = std::move(str);        //5
std::string test3(str_ref);                    //6

std::string 有一個建構函式,它接受 std::string&& 型別的單個引數,通常稱為移動建構函式。但是,表示式 str 的值類別不是右值(特別是它是左值),因此它不能呼叫該建構函式過載。相反,它呼叫 const std::string& 過載,複製建構函式。

第 3 行改變了一切。std::move 的返回值是 T&&,其中 T 是傳入的引數的基本型別。所以 std::move(str) 返回 std::string&&。函式呼叫誰的返回值是右值引用是一個右值表示式(特別是一個 xvalue),因此它可以呼叫 std::string 的移動建構函式。在第 3 行之後,str 已被移除(現在的內容未定義)。

第 4 行將臨時檔案傳遞給 std::string 的賦值運算子。這有一個過載,需要一個 std::string&&。表示式 std::string("new value") 是一個 rvalue 表示式(特別是一個 prvalue),因此它可以呼叫該過載。因此,臨時移動到 str,用特定內容替換未定義的內容。

第 5 行建立一個名為 str_ref 的命名右值引用,引用 str。這是價值類別令人困惑的地方。

請參閱,雖然 str_ref 是對 std::string 的右值引用,但表示式 str_ref 的值類別不是右值。這是一個左值表示式。對真的。因此,不能用表達 str_ref 來呼叫 std::string 的 move 建構函式。第 6 行因此拷貝str 值存入 test3

為了移動它,我們將不得不再次使用 std::move