C++:移动赋值运算符和继承

c++ : move assignement operator and inheritance

提问人:Vince 提问时间:8/26/2020 更新时间:8/26/2020 访问量:146

问:

此代码编译并运行良好:

#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 是 Base 的子类。

移动赋值运算符 A 的代码复制了 Base 的代码。

有没有办法避免这种代码复制?

C++ 继承 move-semantics 赋值运算符

评论

0赞 Al.G. 8/26/2020
使用 a 并且根本不编写这些方法?unique_ptr<int>
1赞 Benny K 8/26/2020
您是否打算拥有两个类型的对象副本?clean_A
0赞 t.niese 8/26/2020
请注意:您知道它不会执行动作,而只是施法?所以没有多大意义,因为它只是一个指针。std::movea_ = std::move(other.a_);a_
0赞 Vince 8/27/2020
@t.niese确保我得到它,你的意思是 a_=std::move(other.a_) 等价于 a_ = other.a_
1赞 t.niese 8/27/2020
对于显示的代码,结果是等效的。 只是一个强制转换,在给定的情况下,在这两种情况下都会复制 的值。所以在这种情况下你可以写。std::mover-valueother.a_a_ = other.a_

答:

1赞 NathanOliver 8/26/2020 #1

更改为 和 to 后,您不再需要编写任何特殊成员函数,因为编译器提供的默认值 Just Work™int* value_;int value_;double* a_;double a_;

如果确实需要动态内存分配,请使用 RAII 类型,如 、 、 等。取而代之的是,因为它们被设计为可以正确复制和/或移动。std::vectorstd::unique_ptrstd::shared_ptr

评论

0赞 Vince 8/26/2020
对于这个特定的例子,这是有道理的,但这只是一些使问题清晰的最小代码。您如何调用基类的移动赋值运算符,考虑到这个最新的并不像这里举例的那样微不足道?
1赞 NathanOliver 8/26/2020
@Vince 诀窍是使用 RAII 类型。那么你什么都不用做,正确的行为就会提供给你。如果确实要调用基类移动赋值,请执行,这将调用基类的移动赋值运算符。Base::operator=(std::move(other));
0赞 Vince 8/26/2020
感谢您的回答,这奏效了!(我的原始代码是操作指向某些进程间共享内存的指针。