0

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

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

cout << s1 << endl;

两种情况下的输出是相同的。“你好”

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

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

我的理解做错了什么。

4

2 回答 2

1

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

string s1 = "hello";
string&& s2 = std::move(s1);  // s2 is a reference
string s3 = std::move(s2);    // now we moved
于 2019-01-27T16:49:21.587 回答
1

一方面,

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移动构造函数或移动赋值运算符之后,“移动自”对象的内容是未指定的。在某些情况下,标准准确地说明了移动操作将做什么,通常使移动对象为空。但是当没有另外指定时,它只表示对象处于“有效但未指定的状态”。并且std::string没有添加任何特定要求,因此未指定状态是结果。因此,在此之后打印s1可能会产生任何结果。(实际上,如果std::string实现使用小字符串优化,你可能会发现它s1并没有改变。)

于 2019-01-27T16:58:03.290 回答