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;
}

明らかに何か問題がありますが、私はビッグ 5 についてあまり詳しくありません...たくさん検索しましたが、それでも答えが見つかりませんでした...

4

1 に答える 1

2

明らかに何か問題があります...答えが見つかりませんでした...

最大の問題は、コピー コンストラクタにあります。

単にポインタをコピーすると、コピーと元の両方が同じ配列を指します。それらの 1 つが破棄されると、デストラクタは指定された配列を削除します。その時点で、他のオブジェクトのポインタは無効になり、その使用は未定義の動作になります。

解決策: 代わりに新しい配列を割り当てます。つまり、浅いコピーではなく、深いコピーを行います。その方法を理解するのに助けが必要な場合は、コピー代入演算子の実装を見てください (ただし、 で簡略化できますstd::copy)。

コピー代入演算子にも欠陥があります。

  • 次の行で上書きされるdata=is.data;ため、意味のない冗長な があります。data
  • コピー コンストラクターを修正して、代入演算子のようにディープ コピーを実行すると、両方のコンストラクターに、新しい配列の割り当てとコンテンツのコピーのための重複したコードが含まれます。重複したコードを持つことは少し悪いです。
  • 演算子は強力な例外保証を提供しません。新しい配列の割り当てで例外がスローされた場合、メンバー ポインターは削除された配列を指します (UB につながります)。割り当てが成功した場合でも、コンテンツのコピーによって例外が発生する場合があります。その場合、部分コピーはロールバックされず、オブジェクトは一貫性のない状態のままになります。強力な例外保証の欠如は、適度に悪いです。

上記の問題の解決策は、一般的なコピー アンド スワップ イディオムを使用してコピー代入演算子を実装することです。


より良い解決策: ほとんど示されていないことから、あなたのクラスは再発明しているように見えますstd::vector。そうする必要はほとんどありません。std::vector代わりに使用してください。

于 2016-06-27T00:03:54.130 に答える