1. ホーム
  2. c++

[解決済み] C++のコピーコンストラクタと=演算子のオーバーロード:共通の関数は可能か?

2023-03-07 08:34:02

質問

コピーコンストラクタは

MyClass(const MyClass&);

と=演算子のオーバーロード

MyClass& operator = (const MyClass&);

はほとんど同じコードで、同じパラメータを持ち、戻り値だけが異なりますが、両者が使用する共通の関数を持つことは可能でしょうか?

どのように解決するのですか?

はい、2つの一般的な方法があります。一つは - 一般的には推奨されませんが -、この方法によって operator= をコピーコンストラクタから明示的に呼び出すことです。

MyClass(const MyClass& other)
{
    operator=(other);
}

しかし、良い operator= を提供することは、古い状態や自己割り当てから発生する問題を処理する際に、困難です。また、すべてのメンバーやベースは、たとえそれが other . これは、すべてのメンバーおよびベースに対して有効であるとは限らず、有効である場合でも意味的に冗長であり、実用的に高価である可能性があります。

ますます一般的になっている解決策は operator= をコピーコンストラクタとスワップメソッドを使って実装することです。

MyClass& operator=(const MyClass& other)
{
    MyClass tmp(other);
    swap(tmp);
    return *this;
}

とかでもいい。

MyClass& operator=(MyClass other)
{
    swap(other);
    return *this;
}

A swap 関数は、内部の所有権を交換するだけで、既存の状態をクリーンアップしたり、新しいリソースを割り当てたりする必要がないため、一般的に簡単に書くことができます。

コピーとスワップのイディオムの利点は、自動的に自己割り当てセーフであり、スワップ操作がno-throwであることを提供し、また強力な例外セーフであることです。

強く例外安全であるために、「手書き」の割り当て演算子は、典型的には、新しいリソースを割り当てているときに例外が発生しても、古い状態に戻ることができるように、割り当て先の古いリソースの割り当てを解除する前に新しいリソースのコピーを割り当てる必要があります。これはすべてコピー アンド スワップでは無料ですが、ゼロから行うには通常より複雑であり、したがってエラーが発生しやすいのです。

注意すべき点は、スワップメソッドが真のスワップであることを確認することであり、デフォルトの std::swap のように、コピーコンストラクタと代入演算子そのものを使用するものではありません。

通常、メンバー単位の swap が使われます。 std::swap は全ての基本型とポインタ型で動作し、'no-throw'が保証されています。ほとんどのスマートポインタもノースロー保証でスワップすることができます。