具有动态内存的类的C ++规则为五

时间:2016-06-26 22:43:51

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

所以我为具有动态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;
}

显然它出现了问题,但我对这五个人并不熟悉......我搜索了很多,但仍然没有找到答案......

1 个答案:

答案 0 :(得分:2)

  

显然它有问题......没找到答案......

最大的错误位于复制构造函数中。

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

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

复制赋值运算符也存在缺陷:

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

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

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