0

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_;
};
Drake Johnson
  • 640
  • 3
  • 19
  • *"is the entire object "moved..." "* Nothing is actually "moved". See [`std::move()` doesn't actually move anything.](https://stackoverflow.com/a/27026280/12002570) – Jason Jun 22 '22 at 12:59
  • @AnoopRana Could you explain why? – Drake Johnson Jun 22 '22 at 13:00
  • 2
    Refer to [`std::move()` doesn't actually move anything.](https://stackoverflow.com/a/27026280/12002570) – Jason Jun 22 '22 at 13:01
  • Re: "the child object is implicitly cast" -- the child object is implicitly **converted**. A cast is never implicit; it's something you write in your source code to tell the compiler to do a conversion. – Pete Becker Jun 22 '22 at 13:02
  • @AnoopRana From my understanding of that article, the underlying char* of each string is still reassigned, making parts or all (which is where my question lies) of `other` unusable. Is that a correct interpretation at all? – Drake Johnson Jun 22 '22 at 13:10
  • @PeteBecker Thank you for the clarifyication. I will fix the question's wording. – Drake Johnson Jun 22 '22 at 13:10

1 Answers1

1

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.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • This is a simplified version of a more involved class I'm writing. I apologize if it was oversimplified in this case, but thank you for your answer. – Drake Johnson Jun 22 '22 at 13:14