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

What happens when std::move is called on a rvalue reference?

考虑以下 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;
}

现在我执行的一个小改动是调用 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;
} 

因此,将右值引用转换为右值引用似乎会引发一些奇怪的事情。 为什么在第一种情况下原始字符串保留其值但在第二种情况下却没有

What happens when std::move is called on a rvalue reference?

std::move 将参数转换为右值引用,它 returns.

Is std::move(r_value_reference_argument) undefined

没有


// Prints "", original is set to the empty string, WHY???

What's happening here?

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

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


OK, but why in the first case the original string is not empty?

因为s是一个左值1,所以使用了拷贝构造函数。复制构造函数不修改原始字符串。

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

// Prints "", original is set to the empty string, WHY???

因为你移动了它。

string constructed = s;

这不会导致移动,因为 s 不是右值 。它是右值引用,但不是右值。如果它有名字,它就不是右值。 Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression.

string constructed = std::move(s);

这会导致移动,因为 std::move(s) 是一个右值:它是一个临时的,它的类型不是左值引用。

程序中没有其他动作(std::move不是动作,是演员)。