0

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

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

4

1 回答 1

2

明明有问题……没找到答案……

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

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

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

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

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

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


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

于 2016-06-27T00:03:54.130 回答