コピーコンストラクタの扱い

この記事は,C++プログラマであるかを見分ける10の質問 - Life like a clown の「コピーコンストラクタおよび代入演算子の扱いにおける戦略について述べよ」に対する回答的な記事です.

C++ では,ユーザが明示的にコピーコンストラクタ,および代入演算子を定義しなかった場合,デフォルトのコピーコンストラクタ,および代入演算子が定義されます.この挙動は,各メンバ変数の値を単にコピーすると言うものなのでポインタなどが絡むと(ポインタ値がコピーされた後でコピー元のクラスで delete が発生するなどの)問題になる場合があります.そのため,コピーコンストラクタについては,

  1. 適切な動作を行うコピーコンストラクタ(および代入演算子)を明示的に定義する.
  2. 適切なコピーコンストラクタを定義できない場合は,コピー不可能にする.

と言う戦略を取ることになります.コピー禁止なクラスを作成する方法は,以下のように private にコピーコンストラクタ,および代入演算子の宣言だけを書いておきます.これによって,どこかでコピーが発生するようなコードが書かれた場合には,コンパイルエラーになってそれを防ぐ事ができます.

class Foo {
public:
    // 必要なメンバ関数などを定義する.
    // ...
private:
    // non-copyable
    Foo(const Foo&);
    Foo& operator=(const Foo&);
};

これをいちいち書くのは面倒と言う事で,Non-copyable クラス などを定義しておき,それを継承して使用すると言う事もしばしば行われます.

I/O のような何らかの資源(にアクセスするためのもの)をメンバ変数に持っている場合など,コピーコンストラクタの挙動をきちんと定義するのが難しいと言うケースはそれなりに存在するため,「コピー禁止にする」と言う選択肢を取る場面にも直々遭遇するのではないかなと思います.