C++ rvalue 右值

示例

右值表达式是任何可以隐式移出的表达式,无论它是否具有标识。

更准确地说,右值表达式可以用作采用类型参数T &&(其中T是的类型expr)的函数的参数。只能将右值表达式作为此类函数参数的参数;如果使用了非右值表达式,则重载解析将选择不使用右值引用参数的任何函数。如果不存在,则会出现错误。

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&重载,即复制构造函数。

第三行改变了一切。的返回值std::move是a T&&,其中T是传入的参数的基本类型。因此返回。返回值是右值引用的函数调用是右值表达式(特别是xvalue),因此它可以调用的move构造函数。在第3行之后,已从移出(其内容现在不确定)。std::move(str)std::string&&std::stringstr

第4行将一个临时变量传递给的赋值运算符std::string。这有一个过载,需要std::string&&。该表达式std::string("new value")是一个右值表达式(特别是prvalue),因此它可以调用该重载。因此,临时文件被移入str,将未定义的内容替换为特定的内容。

第5行创建了一个名为的右值引用str_ref,该引用指向str。这就是价值类别令人困惑的地方。

请参阅,虽然str_ref是rvalue的引用std::string,但表达式的值类别str_ref 不是rvalue。它是一个左值表达式。对真的。因此,无法std::string使用expression调用move的move构造函数str_ref。因此,第6行将的值复制str到中test3。

要移动它,我们将不得不std::move再次雇用。