为什么我们需要在移动构造函数中将右值引用设置为null? [英] Why do we need to set rvalue reference to null in move constructor?

查看:423
本文介绍了为什么我们需要在移动构造函数中将右值引用设置为null?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  // code from https://skillsmatter.com/skillscasts/2188-move-semanticsperfect-forwarding-and-rvalue-references 
class Widget {
public:
Widget(Widget&& rhs)
:pds(rhs.pds)//获取源值
{
rhs.pds = nullptr; //为什么?
}

private:
struct DataStructure;
DataStructure * pds;
}

我不明白设置 rhd.pds nullptr



如果我们删除此行,会发生什么: rhs.pds = nullptr;

解决方案

类的一些细节已被删除。特别是,构造函数动态分配 DataStructure 对象,析构函数释放它。如果在移动过程中,你只是将指针从 Widget 复制到另一个, Widget 同样分配 DataStructure 对象。然后,当这些对象被销毁时,它们都会尝试 delete 。这将给出未定义的行为。为了避免这种情况,正在移动的 Widget 将其内部指针设置为 nullptr



这是实现移动构造函数时的标准模式。您希望将某些动态分配的对象的所有权从一个对象移动到另一个对象,因此您需要确保原始对象不再拥有这些已分配对象。



从这个情况开始,希望将 DataStructure 的所有权从一个 Widget 移动到另一个:

 ┌───────┐
│小部件││小部件│
└───╂────┘└───────┘


┌───────── ────┐
│数据结构│
└──────┘

如果你刚刚复制指针,你会有:

  ──────────
│小部件││小部件│
└───╂────┘└───╂─── ─┘
┗━━━━━━━━━━━━┛

┌────────────┐┐
│数据结构│
└────────────┘

如果然后将原始 Widget 指针设置为 nullptr ,则您具有:

 ┌───────┐
│小部件││小部件│
└──────┘└───╂────┘


┌──────── ─────┐
│数据结构│
└──────┘

所有权已成功转移,且 Widget 可以销毁而不会导致未定义的行为。


//code from https://skillsmatter.com/skillscasts/2188-move-semanticsperfect-forwarding-and-rvalue-references
class Widget {
public:
    Widget(Widget&& rhs)
        : pds(rhs.pds) // take source’s value
    { 
        rhs.pds = nullptr;  // why??
    }

private:
    struct DataStructure;
    DataStructure *pds;
};

I can't understand the reason for setting rhd.pds to nullptr .

What will happen if we remove this line : rhs.pds = nullptr;

解决方案

Some details of the class have been removed. In particular, the constructor dynamically allocates the DataStructure object and the destructor deallocates it. If, during a move, you just copied the pointer from one Widget to another, both Widgets would have pointers to the same allocated DataStructure object. Then, when those objects are destroyed, they would both attempt to delete it. This would give undefined behaviour. To avoid this, the Widget that is being moved from has its internal pointer to set to nullptr.

This a standard pattern when implementing a move constructor. You want to move ownership of some dynamically allocated objects from one object to another, so you need to make sure the original object no longer owns those allocated objects.

Diagrammatically, you start off with this situation, wanting to move ownership of the DataStructure from one Widget to the other:

    ┌────────┐        ┌────────┐
    │ Widget │        │ Widget │
    └───╂────┘        └────────┘
        ┃
        ▼
 ┌───────────────┐
 │ DataStructure │
 └───────────────┘

If you just copied the pointer, you'd have:

    ┌────────┐        ┌────────┐
    │ Widget │        │ Widget │
    └───╂────┘        └───╂────┘
        ┗━━━━━━━━┳━━━━━━━┛
                  ▼
         ┌───────────────┐
         │ DataStructure │
         └───────────────┘

If you then set the original Widget pointer to nullptr, you have:

    ┌────────┐         ┌────────┐
    │ Widget │         │ Widget │
    └────────┘         └───╂────┘
                           ┃
                           ▼
                  ┌───────────────┐
                  │ DataStructure │
                  └───────────────┘

Ownership has successfully been transferred, and when both Widgets can be destroyed without causing undefined behaviour.

这篇关于为什么我们需要在移动构造函数中将右值引用设置为null?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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