右值
rvalue 表示式是可以隱式移出的任何表示式,無論它是否具有標識。
更準確地說,rvalue 表示式可以用作函式的引數,該函式接受 T &&
型別的引數(其中 T
是 expr
的型別)。只有 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
。