之后仍需要使用源对象时调用父移动赋值运算符

Dra*_*son 1 c++ memory inheritance move-semantics

TLDR - 如果是这样,请随意将其标记为重复;我会删除问题。然而,我环顾四周后没有找到任何东西。

考虑以下类:

class Base
{
public:
    Base(std::string var1);

    Base& operator=(Base&& other) noexcept
    {
        if (this != &other)
            var1_ = std::move(other.var1_);
        return *this;
    }

protected:
    std::string var1_;
};

class Child final : public Base
{
public:
    Child(std::string var1, std::string var2);

    Child& operator=(Child&& other) noexcept
    {
        if (this != &other)
        {
            // Take note of HERE for explanation below
            Base::operator=(std::move(other));
            var2_ = std::move(other.var2_);
        }
    }

private:
    std::string var2_;
};
Run Code Online (Sandbox Code Playgroud)

这里有两个类,ChildBase. Child拥有比 多的成员Base。在 的移动赋值运算符中Child,我们有一种情况,我们有额外的成员,这些成员也需要分配给other的成员的值。但是,我们首先将 的内存移动other到父移动赋值运算符,那么该数据不会不可用吗?

我想我只是对(1)我上面的内容是否真的有任何问题感到困惑,(2)如果是这样,为什么它可以工作,因为other它应该在使用之前被移动,以及(3)如果没有,完成我所拥有的任务的最佳方法是什么?

更好的方法是简单地初始化Childfirst的成员,然后将其交给Base移动赋值运算符?这有什么不同吗?

asc*_*ler 6

是的,这是安全的。

首先,请注意不使用移动对象的规则是设计和使用对象的默认准则。这不是语言本身的规则。这是类对象在移出后通常保证的常见做法,包括没有另外指定的标准库类类型(例如std::unique_ptr<T>保证移出的指针持有空指针)。

因此,既然您确切地知道Base::operator=to 的作用other,并且只从 移动other.var1_,那么使用 仍然是安全的other.var2_

这种模式是安全的还有另一个原因,即使您实际上Base::operator=并不确切知道它的作用,或者您想编写Child代码以保持工作,即使细节发生Base变化。一个Child对象包含两个子对象:Base基类子对象和var2_成员子对象。这些对象本质上并不知道其他对象的任何信息。(他们可以通过指针,虚函数等已经手动建立互动对方,到复杂的东西,但那种事情应该记录的Base或已知Child)的Base::operator=(std::move(other));正好从基类子对象的语句移动,而不是从成员子对象,因此成员子对象不受影响,并且 的定义不会Child::operator=(Child&&)对 进行更改Base