在分配字符串时分配右值引用
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
没有改变。)
我正在学习右值引用,我的大脑可能到处都是。但我想测试 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
没有改变。)