【问题标题】:C++ rule of five for class that has dynamic memory具有动态内存的类的 C++ 规则五
【发布时间】:2016-06-26 22:43:50
【问题描述】:

所以我正在为一个具有动态 int 数组的类编写大五

struct intSet {
  int *data;
  int size;
  int capacity;

  intSet();
  ~intSet();
  intSet(const intSet& is);
  intSet(intSet &&is);
  intSet &operator=(const intSet& is);
  intSet &operator=(intSet &&is);
}

到目前为止我得到了什么:

intSet::intSet(const intSet& is){
  this->size=is.size;
  this->capacity=is.capacity;
  this->data=is.data;
}

intSet::intSet(intSet &&is){
  this->size=is.size;
  this->capacity=is.capacity;
  this->data=is.data;
  is.data=nullptr;
}

intSet& intSet::operator=(const intSet& is){
  if(&is!=this){
    size=is.size;
    capacity=is.capacity;
    delete [] data;
    data=is.data;
    data=new int[capacity];
    for(int i=0;i<size;i++){
      data[i]=is.data[i];
    }  
  }
  return *this;
}

intSet& intSet::operator=(intSet &&is){
  if(&is!=this){
    size=is.size;
    capacity=is.size;
    delete [] data;
    data=is.data;
    is.data=nullptr;
  }
  return *this;
}

intSet::~intSet(){
  delete [] this->data;
}

显然有问题但我对五巨头不是很熟悉...我搜索了很多但仍然没有找到答案...

【问题讨论】:

  • 你的意思是“五法则”:en.cppreference.com/w/cpp/language/rule_of_three
  • 您的复制构造函数正在制作浅拷贝,而您的复制赋值运算符正在制作深拷贝。另外,请使用构造函数initializer-list,这不是Java。
  • @BryanChen 所以五巨头是复制构造函数、复制赋值、移动构造函数、移动赋值。
  • 如果可能,请使用shared_ptrunique_ptr 并遵循零规则

标签: c++ copy-constructor move-constructor copy-assignment move-assignment-operator


【解决方案1】:

显然有问题……没有找到答案……

最大的错误在拷贝构造函数中。

当您简单地复制指针时,副本和原始指针都指向同一个数组。当其中一个被销毁时,析构函数删除指向的数组,此时另一个对象中的指针变得无效,并且它的使用将具有未定义的行为。

解决方案:改为分配一个新数组。换句话说:做一个深拷贝,而不是浅拷贝。如果您需要帮助确定如何执行此操作,只需查看您的复制赋值运算符实现(尽管您可以使用 std::copy 进行简化)。

复制赋值运算符也有缺陷:

  • 有一个多余的data=is.data;,这是没有意义的,因为data在下一行被覆盖了。
  • 一旦您修复了复制构造函数以进行深度复制,就像赋值运算符所做的那样,它们都将包含用于分配新数组和复制内容的重复代码。重复代码有点糟糕。
  • 运算符不提供强大的异常保证。如果分配新数组引发异常,则成员指针将指向已删除的数组(导致 UB)。即使分配成功,复制内容也可能导致异常。如果是,则不回滚部分副本,并且对象保持不一致状态。缺乏强有力的异常保证是中度糟糕的。

解决上述问题的方法是使用流行的复制和交换习语来实现复制赋值运算符。


更好的解决方案:从所显示的内容来看,您的班级似乎正在重新发明std::vector。几乎没有必要这样做。只需改用std::vector

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-28
    • 2011-06-14
    • 1970-01-01
    • 2016-07-29
    • 1970-01-01
    • 2011-11-13
    相关资源
    最近更新 更多