0

This code compiles and runs fine:

#include <iostream>

class Base
{
  public:
  Base(int value)
  : clean_(true)
  {
      value_ = new int;
      *value_ = value;
  }
  ~Base()
  {
      if(clean_)
        delete value_;
  }
  Base(Base&& other) noexcept 
  : value_{std::move(other.value_)},
    clean_(true)
  {
      other.clean_=false;
  }
  Base& operator=(Base&& other) noexcept
  {
      value_ = std::move(other.value_);
      other.clean_=false;
      clean_=true;
  }
  void print()
  {
      std::cout << value_ << " : " << *value_ << std::endl;
  }
  
  int* value_;
  bool clean_;
    
};

class A : public Base 
{
  public:
  A(int v1, double v2) : Base(v1)
  {
      a_ = new double;
      *a_ = v2;
  }
  A(A&& other) noexcept
  : Base(std::forward<Base>(other)),
    a_(std::move(other.a_))
  {}
  A& operator=(A&& other) noexcept
  {
      // should not the move assignment operator
      // of Base be called instead ? 
      // If so: how ?
      this->value_ = std::move(other.value_);
      other.clean_=false;
      this->clean_=true;
      a_ = std::move(other.a_);
  }
  void print()
  {
      std::cout << this->value_ << " "
                << *(this->value_) << " "
                << a_ << " " << *a_ << std::endl;
  }

  double* a_;
  bool clean_;
    
};

A create_a(int v1,double v2)
{
    A a(v1,v2);
    return a;
}

int main()
{
    Base b1(20);
    b1.print();
    
    Base b2 = std::move(b1);
    b2.print();
    
    A a1(10,50.2);
    a1.print();
    
    A a2 = std::move(a1);
    a2.print();
    
    A a3 = create_a(1,2);
    a3.print();
}

A is a subclass of Base.

The code of the move assignment operator of A replicates the one of Base.

Is there a way to avoid this replication of code ?

Vince
  • 3,979
  • 10
  • 41
  • 69
  • Use a `unique_ptr` and don't write these methods at all? – Al.G. Aug 26 '20 at 12:55
  • 1
    Do you intend to have two copies of `clean_` in objects of type `A`? – Benny K Aug 26 '20 at 12:55
  • As a note: you are aware that `std::move` does not perform a move, but that it is just a cast? So `a_ = std::move(other.a_);` does not make to much sense as `a_` is just a pointer. – t.niese Aug 26 '20 at 15:47
  • @t.niese to make sure I get it, you mean *a_=std::move(other.a_)* is equivalent to *a_ = other.a_* ? – Vince Aug 26 '20 at 18:41
  • 1
    For the shown code the outcome it equivalent. `std::move` is just a cast to an `r-value`, and the value of `other.a_` will be copied in both cases in the given case. So you can just write `a_ = other.a_` in this case. – t.niese Aug 27 '20 at 07:01

1 Answers1

1

Change int* value_; to int value_; and double* a_; to double a_; and you no longer need to write any of the special member functions as the compiler provided defaults Just Work™

If you really need dynamic memory allocation, then use a RAII type like std::vector, std::unique_ptr, std::shared_ptr, ect. in its place since they are designed to be copied and or moved correctly.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • For this specific example, this makes sense, but this is just some minimal code for making question clear. How to you call the move assignement operator of the Base class, considering this latest is not as trivial as the one exemplified here ? – Vince Aug 26 '20 at 13:02
  • 1
    @Vince The trick is to use RAII types. Then you don't have to do anything, the correct behavior will be provided to you. If you really want to call the base class move assignment, then do `Base::operator=(std::move(other));` and that will call the base's move assignment operator. – NathanOliver Aug 26 '20 at 13:06
  • thanks for the answer, this worked ! (My original code is manipulating pointers to some inter-process shared memory.) – Vince Aug 26 '20 at 13:11