1

コンストラクターで整数 (_pPtrMem などのクラス メンバーが指す) に動的にメモリを割り当て、デストラクタで同じものを解放するクラス A があります。浅いコピーを避けるために、代入演算子とコピー コンストラクターをオーバーロードしました。代入演算子がオーバーロードされる広く使用されている方法は次のとおりです。

A& operator = (const A & iToAssign)
{
  if (this == & iToAssign)  // Check for self assignment
    return *this;
  int * pTemp = new int(*(iToAssign._pPtrMem)); // Allocate new memory with same value
  if (pTemp)
  {
    delete _pPtrMem;  // Delete the old memory
    _pPtrMem = pTemp; // Assign the newly allocated memory
  }
  return *this;   // Return the reference to object for chaining(a = b = c)
}

同じことを実装する別の方法は次のとおりです。

A& operator = (const A & iToAssign)
{
  *_pPtrMem= *(iToAssign._pPtrMem); // Just copy the values
  return *this;   
}

2 番目のバージョンは比較的単純で高速 (解放、メモリの割り当てなし) であるため、広く使用されていないのはなぜですか? 私が理解できない問題はありますか?

また、連鎖 (a = b = c) の代入演算子から同じ型のオブジェクトを返します... したがって、*thisを返す代わりに、 iToAssignオブジェクトを返すことは問題ありません。

4

5 に答える 5

6

通常、コピー代入演算子を実装する最良の方法はswap()、クラスに関数を提供し (または、必要に応じて標準の関数を使用し)、コピー コンストラクターを介してコピー代入演算子を実装することです。

A& A::operator= (A iToAssign)  // note pass by value here - will invoke copy constructor
{
  iToAssign.swap(*this);
  return *this;
}
// void swap(A& other) throws() // C++03
void A::swap(A& other) noexcept
{
    std::swap(_pPtrMem, other._pPtrMem);
}

これにより、コピー代入演算子とコピー コンストラクターが発散しないようになります (つまり、一方を変更して他方を変更するのを忘れることはありません)。

于 2013-03-12T08:00:21.340 に答える
2

いいえ、実装に問題はありません。しかし、1 つの整数ダイナミックを割り当てることは、少なくとも非常に特別です。

フリー ストアに単一の整数を割り当てる人はいないため、この実装は広く使用されていません。通常、コンパイル時に可変長が不明な配列には、動的に割り当てられたメモリを使用します。この場合、ほとんどの場合、std::vector を使用することをお勧めします。

いいえ、別のオブジェクトを返すのは問題ありません。同一性は平等と同じではありません:

T a, b, d;
T& c = a = b;
c = d; // should change a, not b 

3 行目が b に変わると思いますか?

またはイベントより良い例:

T a;
T& b = a = T();

これにより、ダングリング参照が発生し、一時的で破壊されたオブジェクトが参照されます。

于 2013-03-12T08:05:04.917 に答える
1

最初のバージョンは_pPtrMem、動的に割り当てられた配列などの基本型へのポインタである場合に使用されます。ポインターが、正しく実装された代入演算子を持つ単一のオブジェクトを指している場合、2 番目のバージョンでも同様に機能します。しかし、その場合、ポインターを使用する必要はまったくないと思います。

于 2013-03-12T07:59:48.337 に答える
0

この場合、2 番目の実装の方がはるかに優れています。ただし、オブジェクトで動的を使用する通常の理由は、サイズが異なる可能性があるためです。(もう 1 つの理由は、浅いコピーの参照セマンティクスが必要なためです。) そのような場合、最も簡単な解決策、(自己割り当てのテストなしで) 最初の割り当てを使用することです。オブジェクトによっては、新しい値が収まる場合は、既に存在するメモリを再利用することを検討する場合があります。多少複雑になりますが(適合するかどうかをテストし、適合しない場合でも割り当て/コピー/削除を行う必要があるため)、場合によってはパフォーマンスを向上させることができます.

于 2013-03-12T09:45:05.867 に答える
0

2 番目のケースでは、_pPtrMemが最初に割り当てられていなかった場合、行

*_pPtrMem= *(iToAssign._pPtrMem); // Just copy the values

無効なメモリ位置への割り当てが発生しています (セグメンテーション違反の可能性があります)。_pPtrMemこれは、この呼び出しの前にメモリが割り当てられている場合にのみ機能します。

于 2013-03-12T07:59:05.543 に答える