其他分享
首页 > 其他分享> > 在c 11中为什么在std :: move之后没有权利使用移动变量?

在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