在分配字符串时分配右值引用

Assigning rvalue references while assigning string

我正在学习右值引用,我的大脑可能到处都是。但我想测试 std::move 和右值引用,下面是代码片段

string s1 = "hello";
{
    string&& s2 = std::move(s1);
    cout << s2 << endl;
}

cout << s1 << endl;

两种情况下的输出是相同的。 "hello"

我希望在块内部创建 s2 时,它会调用移动赋值运算符,从而确保 s1 没有指向任何东西,但那没有发生。

我的理由是字符串在其内部携带一个指向 char 的指针,因此当调用移动指针时,它会将内存分配从 s1 移动到 s2,因此当我从 s1 移动到 s2 时,打印 s1 应该会导致问题。

我的理解哪里做错了

s2 仍然是一个引用,这意味着您的代码中没有调用其他构造函数或赋值运算符。您可以使用 s2 调用移动构造函数或移动分配。在该构造函数中,移动魔术将发生(即使旧字符串之后可能仍包含原始文本)。

string s1 = "hello";
string&& s2 = std::move(s1);  // s2 is a reference
string s3 = std::move(s2);    // now we moved

一方面,

string&& s2 = std::move(s1);

根本不是作业;这是一个初始化。

并且它是引用的初始化,而不是对象。你的程序里只有一个std::string,名字叫s1。由于您将 s2 声明为引用,因此它引用了其他某个对象 - 这里是 s1。所以根本不需要调用移动构造函数或移动赋值运算符,并且s1无法更改。

如果您改写

string s2 = std::move(s1);

那么这实际上会创建第二个 std::string 对象,名为 s2。它使用移动构造函数进行初始化。

或者如果 = 用于先前声明的对象,而不是在声明后立即引入初始化程序,那么它是一个真正的赋值:

string s2;
s2 = std::move(s1);

这里s2首先使用std::string默认构造函数创建,然后使用std::string移动赋值运算符修改。

但请注意,在 std::string 移动构造函数或移动赋值运算符之后,"moved-from" 对象的内容是 未指定的 。在某些情况下,标准会准确说明移动操作将执行的操作,通常会使移出的对象为空。但是当没有特别说明的时候,它只是说对象在"valid but unspecified state"中。并且 std::string 没有添加任何特定要求,因此结果为未指定状态。所以在此之后打印 s1 可能会产生任何结果。 (实际上,如果 std::string 实现使用小字符串优化,您可能会发现 s1 没有改变。)