在c ++ 11中,为什么不正确在std :: move之后使用移动变量? [英] In c++11 why not right to use moved variable after std::move?

查看:54
本文介绍了在c ++ 11中,为什么不正确在std :: move之后使用移动变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为 std :: move(v)仅仅是像

static_cast<T&&>(v)

其中 T v 的类型.但是,为什么移动变量不是原始对象的引用?

where T is the type of v. But why the moved variable not a reference of the original object?

例如,当 o1 被移动"到 o2 时,为什么我们不能访问 o2 o1.str _ 了吗?

For example, when o1 is "moved" to o2, why can't we access the str_ of o2 through o1.str_ any more?

#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"移动?但是为什么这会有所不同?

So the root cause is the "std::string" move? But why this makes different?

推荐答案

让我们暂时忘记您的课程,仅以 std :: string 为例.

Let's forget about your class for now, and just take an std::string as an example.

std::string s1{"Hello, World!"};  // 1
std::string s2{s1};               // 2
std::string s3{std::move(s1)};    // 3

在第1行上,您构造了一个 std :: string 对象.在第2行上,您将 s s1 复制到 s2 .现在, s1 s2 都将包含它们自己的字符串"Hello,World!" 的副本.此副本由 std :: string (或 std :: basic_string< char> )的副本构造函数完成,该副本构造函数不会修改参数.

On line 1 you've constructed an std::string object. On line 2 you're copying s1 to s2. Now both s1 and s2 will contain their own copies of the string "Hello, World!". This copy is being done by the copy constructor of std::string (or std::basic_string<char>) which does not modify the argument.

basic_string(basic_string const& other);

在第3行上,您将 s1 的内容移动 s3 .为此,您首先将 s1 强制转换为 std :: string&& (这就是 std :: move 的作用).由于进行了这种强制转换,因此调用现在将匹配 std :: string 的move构造函数,而不是像上一行那样的copy构造函数.

On line 3 you're moving the contents of s1 to s3. In order to do this, you first cast s1 to std::string&& (this is what std::move does). Because of this cast, the call will now match std::string's move constructor, instead of the copy constructor like the previous line.

basic_string(basic_string&& other) noexcept;

由于总是使用字符串的右值实例调用该构造函数,因此它具有从参数中窃取资源的许可.因此,内部构造函数将简单地复制一些指针,将其复制到 s1 分配的来存储字符串,并设置 s1 实例,使其现在为空.因此, s3 现在拥有字符串.

This constructor, because it's always called with an rvalue instance of the string, has license to steal resources from the argument. So internally the constructor will simply copy over some pointers to the memory that was allocated by s1 to store the string, and set the state of the s1 instance such that it is now empty. Thus s3 now owns the string.

当您在类实例内移动 string 数据成员时,也会发生同样的事情.这就是为什么从 std :: string 对象移动的对象在打印时显示为空的原因.

The same things are happening when you move the string data member within your class instance. That's why the moved from std::string object appears empty when you print it.

如果 std :: string 实现使用小字符串优化,则执行的操作会有所不同,但这只是实现细节.从概念上讲,这两种情况都如上所述.

The operations performed are different if the std::string implementation uses small string optimization, but that is just an implementation detail. Conceptually, both cases work as described above.

这篇关于在c ++ 11中,为什么不正确在std :: move之后使用移动变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆