オブジェクトの初期化と代入
ライブラリを書いていると、自作のクラスを便利に使えるようにコンストラクタ・コピーコンストラクタ・コピー代入演算子をたくさん用意したくなることがあります。でも、これらが一体いつどこで呼ばれるのか資料が少なかったので、また仕様書を読んでみました。そんなわけで以下メモです。
注:この記事ではunionやPOD・非PODの区別は書いていません。
初期化と代入文
まず大原則として、初期化と代入文は全くの別物として扱われます。例えば、下のコードの3行目は代入文のように見えますが、これは単に初期化の表記に=記号を使っているだけで、代入文ではありません。
T t; //初期化子のない初期化 T t(1.0); //直接の初期化 T t = u; //コピー表記の初期化 t = u; //代入文
ここではそれぞれの構文の区別のために、コメントに書いた名前で呼びたいと思います。
初期化について
初期化子のない初期化では、クラスの場合はコンストラクタが呼ばれ、それ以外では不確定な値を取ります。
直接の初期化はT t(1.0)のような場合の他に、T(1.0)のような書き方・new・static_cast・メンバ初期化子による初期化時にも行われます。また、コピー表記の初期化はT t = u;のような場合の他に、関数の引数・関数の戻り値・例外送出・例外ハンドリング・{}を使った初期化のときにも行われます。
クラスを初期化するとき、直接の初期化の場合と「コピー表記の初期化で、両方が同じ型であるか、ある型をその派生した型で初期化する場合」に対しては対応するコンストラクタが直接呼ばれます。それ以外のクラスの初期化では、対象の型へのユーザ定義の変換がされた後、対応するコンストラクタが呼ばれます。
非クラスをクラスで初期化する場合には、変換関数が呼ばれます。それ以外の場合は、標準の型変換が行われます。
代入文について
代入文では、クラスへの代入にはコピー代入演算子が使用され、それ以外では暗黙の標準型変換が使用されます。