在c 11中为什么在std :: move之后没有权利使用移动变量?
作者:互联网
因为std :: move(v)只是一个类似的演员
static_cast<T&&>(v)
其中T是v的类型.但是为什么移动的变量不是原始对象的引用?
例如,当o1“移动”到o2时,为什么我们不能再通过o1.str_访问o2的str_?
#include <string>
#include <iostream>
struct MyClass {
std::string str_;
MyClass(MyClass const &) = delete;
MyClass &operator=(MyClass const &) = delete;
MyClass(MyClass &&o) : str_(std::move(o.str_)) {}
MyClass(std::string const &str) : str_(str) {}
};
int main(void) {
MyClass o1 = MyClass("o1");
MyClass o2(std::move(o1));
std::cout << "o1: " << o1.str_ << "\n"
<< "o2: " << o2.str_ << std::endl;
return 0;
}
输出:
o1:
o2: o1
更新:
看来,当我改变
MyClass(MyClass &&o) : str_(std::move(o.str_)) {}
至
MyClass(MyClass &&o) : str_(o.str_) {}
输出将是:
o1: o1
o2: o1
那么根本原因是“std :: string”的举动?但为什么这会有所不同?
解决方法:
让我们暂时忘掉你的类,并以std :: string为例.
std::string s1{"Hello, World!"}; // 1
std::string s2{s1}; // 2
std::string s3{std::move(s1)}; // 3
在第1行,您构建了一个std :: string对象.在第2行,你将s1复制到s2.现在s1和s2都将包含自己的字符串“Hello,World!”的副本.此副本由std :: string(或std :: basic_string< char>)的复制构造函数完成,该复制构造函数不修改参数.
basic_string(basic_string const& other);
在第3行,您将s1的内容移动到s3.为此,首先将s1转换为std :: string&& (这是std :: move的作用).由于这个强制转换,调用现在将匹配std :: string的移动构造函数,而不是像前一行那样的复制构造函数.
basic_string(basic_string&& other) noexcept;
这个构造函数,因为它始终使用字符串的rvalue实例调用,具有从参数中窃取资源的许可.因此,内部构造函数将简单地复制一些指针,这些指针指向由s1分配的内存以存储字符串,并设置s1实例的状态,使其现在为空.因此s3现在拥有该字符串.
在类实例中移动字符串数据成员时,会发生同样的事情.这就是为什么从std :: string对象移动时打印它时显示为空的原因.
†如果std :: string实现使用小字符串优化,则执行的操作会有所不同,但这只是一个实现细节.从概念上讲,两种情况都如上所述起作用.
标签:c,c11,move,rvalue-reference 来源: https://codeday.me/bug/20190728/1561558.html