在之后仍需要使用源对象时调用父移动分配运算符

Calling parent move assignment operator when source object still needs to be used after

本文关键字:调用 移动 运算符 分配 对象 之后      更新时间:2023-10-16

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_;
};

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

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

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

是的,这是安全的。

首先,请注意,关于不使用移自对象的规则是设计和使用对象的默认准则。这不是语言本身的规则。对于类对象在从中移出后通常保证的内容,包括未另行指定的标准库类类型(例如std::unique_ptr<T>保证移自指针包含空指针),这是常见的做法。

因此,由于您确切地知道Base::operator=other的作用,并且仅从other.var1_移动,因此使用other.var2_仍然是安全的。

这种模式是安全的还有另一个原因,即使你实际上并不确切知道Base::operator=做什么,或者你想编写Child代码来继续工作,即使Base的细节发生了变化。Child对象包含两个子对象:Base基类子对象和var2_成员子对象。这些对象本质上对另一个对象一无所知。(他们可以通过指针、虚函数等手动设置彼此之间的交互,以使事情复杂化,但这种事情应该记录在BaseChild中已知)Base::operator=(std::move(other));语句仅从基类子对象移动,而不是从成员子对象移动,因此成员子对象不受影响,并且Child::operator=(Child&&)的定义可以安全地防止更改Base