我正在学习有关右值引用的知识,我的大脑可能遍地开花。但是我想测试std :: move和rvalue引用,下面是代码片段
string s1 = "hello";
{
string&& s2 = std::move(s1);
cout << s2 << endl;
}
cout << s1 << endl;
在两种情况下输出都是相同的。 “你好”
我希望在创建s2时在块内将其称为移动分配运算符,从而确保s1没有指向任何东西,但这没有发生。
我的合理性是,字符串在其中携带了一个指向char的指针,因此,当调用move指针时,它将把内存分配从那里移走。因此,当我从s1移到s2时,打印s1应该会引起问题。>
根据我的理解,我做了什么错事。
答案 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
尚未更改。)