在右值引用上调用 std::move 时会发生什么?

mer*_*114 3 c++ move rvalue-reference move-semantics c++11

考虑以下 C++ 程序:

string construct(string&& s) {
    // Passing a r-value reference as an argument to the assignment operator
    string constructed = s;
    return constructed;
}

int main() {
    string original = "Hello";
    string temp1 = construct(std::move(original));

    printf("%s\n", original.c_str()); // Prints "Hello", so original has not changed
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在我执行的一个小变化是在 r 值引用参数上调用 std::move :

string constructWithMove(string&& s) {
    // Passing a cast to an r-value reference using r-value reference as an argument.
    string constructed = std::move(s);
    return constructed;
}

int main() {
    string original = "Hello";
    string temp = constructWithMove(std::move(original));

    printf("%s\n", original.c_str()); // Prints "", original is set to the empty string, WHY???
    return 0;
} 
Run Code Online (Sandbox Code Playgroud)

所以看起来将 r 值引用转换为 r 值引用会引发一些特殊的事情。为什么在第一种情况下原始字符串保留其值但在第二种情况下不保留

eer*_*ika 5

在右值引用上调用 std::move 时会发生什么?

std::move 将参数转换为右值引用,并返回该引用。

std::move(r_value_reference_argument)未定义

不。


// Prints "", original is set to the empty string, WHY???
Run Code Online (Sandbox Code Playgroud)

这里发生了什么事?

因为结果来自std::mover 值(更具体地说是 x 值)。并被传递给 的构造函数std::string,它调用移动构造函数。您正在观察从中移出的字符串。

请注意,这种移动使原始字符串处于未指定状态。不能保证它是空的,甚至与它过去包含的内容也不不同。也不保证不为空。


好的,但为什么在第一种情况下原始字符串不为空?

因为s是左值1,因此使用了复制构造函数。复制构造函数不修改原始字符串。

1简单的经验法则:如果它是一个名称,那么它就是一个左值。

  • @mercury0114,“s”是左值。它的类型是无关紧要的。 (2认同)
  • @mercury0114:因此,“stringbuilt = s;”调用复制构造。除非您显式使用“std::move”,否则编译器不会从它移动,因为函数中的后面一行也可能引用“s”并期望它仍然处于作为函数参数传递的状态。使用 std::move() 可以有效地向编译器保证您理解这一点并进行相应的编码。 (2认同)