web-dev-qa-db-ja.com

自己割り当てが役立つ状況はありますか?

割り当て演算子を実装する場合、少なくともクラスに非PODメンバーがある場合は、自己割り当てから保護する必要があることが一般的に知られています。通常は次のとおりです(または同等です)。

_Foo& operator=(const Foo& other)
{
  if (&other == this)
     return *this;
  ... // Do copy
}
_

自己割り当て保護を自動的に挿入しない理由は何ですか?自己割り当てが重要で実用的でない何かを行うユースケースはありますか?

_Foo& operator=(const Foo& other)
{
  if (&other == this)
  {
    // Do something non-trivial
  }
  else
  {
    // Do copy
  }
  return *this;
}
_

今までに回答とディスカッションを要約するには

自明ではない自己割り当ては、本当に役立つことはありません。提案された唯一のオプションは、いくつかの論理エラーを検出するためにassertをそこに置くことでした。しかし、a = std::min(a, b)のようなかなり正当な自己割り当てのケースがあるため、このオプションでさえ非常に疑わしいものです。

しかし、自明な自己割り当てには2つの可能な実装があります。

  1. _&other == this_の場合は何もしません。常に機能しますが、余分な分岐のためにパフォーマンスに悪影響を及ぼす可能性があります。ただし、ユーザー定義の代入演算子では、ほとんどの場合明示的にテストを行う必要があります。
  2. 各メンバーをそれ自体にコピーします。これはデフォルトで行われることです。メンバーがデフォルトの代入演算子も使用する場合は、追加の分岐が必要ないため、高速になる可能性があります。

C++標準がユーザー定義の代入演算子で_&other != this_であることを保証できなかった理由はまだわかりません。分岐しない場合は、デフォルトの演算子を使用します。オペレーターを再定義する場合、とにかくいくつかのテストが必要です...

24
aparpara

自己割り当て保護は、スキップされたコードがそれ自体に適用されたときに危険なタイプの場合にのみ必要です。個々のオブジェクトには、コピーしたくないある種の識別子があるため、ユーザー指定の代入演算子がある場合を考えてください。自己割り当ての場合は、他の値を「コピー」できます。したがって、非表示の自己割り当てテストを挿入すると、無意味でコストがかかる可能性のある条件付きブランチが追加されます。

だから、それは自己割り当てが有用であるということではありません。それは常に保護を必要としない自己割り当てについてです。

さらに、C++は通常、明示的に要求しない限り、そのようなコードをコードに追加することを好みません。通常、関数の一部ではなく、関数全体の観点から行われます。ブロックの最後のデストラクタ呼び出しでさえ、破壊するオブジェクトをスタックに置くときに要求したものです。

19
Nicol Bolas

それが起こり得るアルゴリズムがあります。

  1. Lhsとrhsは同じであるかもしれませんが、チェックよりも割り当てを行う方が簡単です。たとえば、a = std::min(a,b);を検討します。if (a > b) a = b;よりも単純で、おそらく理解が容易です。同様の事柄のより複雑な例を検討してください。

  2. Lhsとrhsが同じであるかどうかは、どこかから渡された可能性があるため、わかりません。

発生する可能性のあるこれらのアルゴリズムは珍しくありません。

18
davidbak