I was wondering if the following code was safe, considering the child object is implicitly converted to type Parent
and then moved from memory. In other words, when passing other
to Parent::operator=(Parent&&)
from Child::operator(Child&&)
, is the entire object "moved" with the parent call, or just the underlying Parent
object?
class Parent
{
public:
// Constructors
Parent& operator=(Parent&& other) noexcept
{
if (this == &other)
return *this;
str1_ = std::move(other.str1_);
str2_ = std::move(other.str2_);
return *this;
}
protected:
std::string str1_, str2_;
};
class Child : public Parent
{
public:
// Constructors
Child& operator=(Child&& other) noexcept
{
if (this == &other)
return *this;
// Are the following 2 lines memory safe?
Parent::operator=(std::move(other));
str3_ = std::move(other.str3_);
return *this;
}
private:
std::string str3_;
};
CodePudding user response:
What you are doing is safe. You are just passing a reference to the base-class subobject to the base assignment operator. std::move
doesn't move anything. It just makes an xvalue out of an lvalue, so that a rvalue reference may bind to it. The binding here is to a subobject because Parent
is a base class type of Child
.
In fact you are exactly replicating the behavior that a defaulted move assignment operator would have (except that it wouldn't check for self-assignment, which is pointless if you are only forwarding to other assignment operators), which begs the question why you are defining it at all? Just follow the rule-of-zero and don't declare a move assignment operator.
This goes for both Parent
's and Child
's move assignment operator.