問題の歴史:
従来のC++では、クラスのメンバーはコンストラクタの初期化リストでのみ初期化されました。C++11からは、クラス内の宣言でデフォルト値を指定する(メンバー初期化子)ことができ、コードの可読性と安全性が向上しました。
問題:
メンバーの値を設定する方法はいくつかあります:宣言内(in-class)、コンストラクタの初期化リストを通して、コンストラクタの本体内で。これらの異なる方法はパフォーマンスとセマンティクスに影響を与え、誤解すると不要なコピーやデフォルトのデストラクタ、定数や参照に関するエラーが発生します。
解決策:
class MyClass { int x = 42; };
class MyClass { const int y; MyClass(int val) : y(val) {} // そうでなければコンパイルエラー };
class MyClass { std::string s; MyClass() { s = "hello"; } // まずdefault、次に代入 };
主な特徴:
メンバーの初期化順序は、クラス内での宣言順序で行われますか?それとも初期化リストの順序ですか?
初期化の順序は常に、クラス内で宣言されている順序であり、初期化リストの順序ではありません。順序の違反は依存メンバーに危険です。
class A { int x = 1; int y = 2; A() : y(10), x(20) {} }; // xはyよりも先に初期化されますが、リストの順序には関係ありません
初期化リストで初期化されなかった定数メンバーをコンストラクタの本体内で初期化することはできますか?
いいえ。定数は初期化リストでのみ初期化されます。コンストラクタの本体での代入はコンパイルエラーです。
クラス内でin-class initializerを使用してメンバーにデフォルト値を指定し、コンストラクタの初期化リストでそれを上書きした場合、どうなりますか?
コンストラクタの初期化リストの値が使用されます。デフォルト値は、リストが何も指定しなかった場合にのみ使用されます。
class C { int x = 10; C() : x(20) {} // xは20になります };
クラスがファイルを処理しています。ファイルはstd::ofstreamとして宣言され、コンストラクタの本体内で初期化されます。危険:デフォルトコンストラクタで無効なstd::ofstreamが作成される可能性があり、ファイル操作のエラーが発生します。
利点:
欠点:
ファイルは初期化リストで初期化されており、無効な状態のファイルの誤った使用を防ぎ、デフォルトデータを持つメンバーはインクラス初期化子を使用します。
利点:
欠点: