C++ コピーコンストラクタって?
オブジェクト指向を扱う言語で、オブジェクトを初期化する際に自動的に呼ばれるメソッドはコンストラクタ。
オブジェクトを削除する際呼ばれるのはデストラクタ。影は薄いがコピーコンストラクタなるものが存在するのはご存知だろうか。入門書では前者2つは大きく取り上げられているが、コピーコンストラクタはなんだか影が薄いような気が...
実はとっても大事なコピーコンストラクタについてまとめたいと思います。
一応C++のコードで解説していますが、考え方としてはオブジェクト指向を採用している言語では共通だと思います。
まず宣言方法から
class Obj {
public:
Obj(){ printf("コンストラクタが呼ばれたよ"); } // コンストラクタ
~Obj(){} // デストラクタ
Obj(const Obj &obj){ printf("コピーコンストラクタが呼ばれたよ"); } // コピーコンストラクタ
};
コピーコンストラクタが、呼ばれるタイミング
- オブジェクトの初期化時
- オブジェクトを関数に値渡しするとき
- 関数からオブジェクトを値渡しする時
まとめるとオブジェクトのコピーが行われたときです
名前の通りですね(笑)
1のケース
Aの初期化を行った際にコンストラクタは呼び出されます。
Obj* obj = new Obj();
Obj obj2;
// 結果
// コンストラクタが呼ばれたよ
// コンストラクタが呼ばれたよ
コピーコンストラクタはこんな時呼ばれます。
Obj obj;
Obj obj2 = obj;
// 結果
// コンストラクタが呼ばれたよ
// コピーコンストラクタが呼ばれたよ
obj2に対しobjのコピーを行っています。このような場合コピーコンストラクタは呼ばれることになります。
2のケース
Obj obj;
func(obj);
// 結果
// コンストラクタが呼ばれたよ
// コピーコンストラクタが呼ばれたよ
こういった状況の場合funcに渡されるのはobjのコピーとなりますからコピーコンストラクタが呼ばれることになります。
3のケース
これも2のケースと同様の原理ですが、関数がなにか値を返すときは、ポインタでない限りオブジェクトのコピーとなります。なのでコピーコンストラクタが呼ばれることになります。
Obj func(){
return Obj();
}
int main() {
Obj a = func();
}
// 結果
// コンストラクタが呼ばれたよ。
// コピーコンストラクタが呼ばれたよ。
このケースでは関数の中で、Objが作られることにより、コンストラクタが呼ばれ、関数からObjを返す段階で、コピーが取られるので、コピーコンストラクタがよびだされることになりました。
ざっくり概要だけ紹介しましたが、ぱっと使い所がわからないような気がしますよね(笑)
しかし意外と重要な役割を持っているのです。次回はより詳しいコピーコンストラクタの使用法について、紹介したいと思います。