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

时间:2019-01-27 16:46:25

标签: c++ string stdmove

我正在学习有关右值引用的知识,我的大脑可能遍地开花。但是我想测试std :: move和rvalue引用,下面是代码片段

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

cout << s1 << endl;

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

我希望在创建s2时在块内将其称为移动分配运算符,从而确保s1没有指向任何东西,但这没有发生。

我的合理性是,字符串在其中携带了一个指向char的指针,因此,当调用move指针时,它将把内存分配从那里移走。因此,当我从s1移到s2时,打印s1应该会引起问题。

根据我的理解,我做了什么错事。

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

一方面,

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

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

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

如果您改为写信

string s2 = std::move(s1);

这实际上将创建另一个名为std::string的{​​{1}}对象。使用move构造函数对其进行初始化。

或者如果在先前声明的对象上使用s2,而不是在声明之后立即引入初始化程序,则它是真正的赋值:

=

这里string s2; s2 = std::move(s1); 首先使用s2默认构造函数创建,然后使用std::string移动分配运算符进行修改。

但是请注意,在std::string移动构造函数或移动赋值运算符之后,“移出”对象的内容为未指定。在某些情况下,标准会准确说明移动操作将执行的操作,通常会使从中移出的对象为空。但是,如果没有另外指定,则仅表示对象处于“有效但未指定状态”。 std::string并没有添加任何特定要求,因此未指定状态是结果。因此,在此之后打印std::string可能会导致任何结果。 (实际上,如果s1实现使用小字符串优化,则可能会发现std::string尚未更改。)