为什么我们需要在移动构造函数中将rvalue引用设置为null?

LxL*_*LxL 10 c++ rvalue-reference move-constructor move-semantics c++11

//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;
};
Run Code Online (Sandbox Code Playgroud)

我不明白设置的原因rhd.pdsnullptr.

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

Jos*_*eld 14

该课程的一些细节已被删除.特别是,构造函数动态分配DataStructure对象,析构函数释放它.如果在移动过程中,您只是将指针从一个复制Widget到另一个,则两个Widgets都将指向同一个已分配的DataStructure对象.然后,当这些物体被摧毁时,它们都会尝试delete它.这会产生未定义的行为.为了避免这种情况,Widget正在移动它的内部指针设置为nullptr.

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

从图中可以看出,您DataStructure要从这种情况开始,希望将所有权从一个Widget转移到另一个:

    ??????????        ??????????
    ? Widget ?        ? Widget ?
    ??????????        ??????????
        ?
        ?
 ?????????????????
 ? DataStructure ?
 ?????????????????
Run Code Online (Sandbox Code Playgroud)

如果您只是复制指针,您将拥有:

    ??????????        ??????????
    ? Widget ?        ? Widget ?
    ??????????        ??????????
        ??????????????????
                  ?
         ?????????????????
         ? DataStructure ?
         ?????????????????
Run Code Online (Sandbox Code Playgroud)

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

    ??????????         ??????????
    ? Widget ?         ? Widget ?
    ??????????         ??????????
                           ?
                           ?
                  ?????????????????
                  ? DataStructure ?
                  ?????????????????
Run Code Online (Sandbox Code Playgroud)

已成功转移所有权,并且当两个Widgets都可以被销毁而不会导致未定义的行为.