@SebastianRedlはすでに簡単で直接的な回答を提供しましたが、いくつかの追加の説明が役立つかもしれません。
TL; DR =コンストラクターをシンプルに保つためのスタイルルールがあり、それには理由がありますが、それらの理由は主に歴史的な(または単に悪い)コーディングスタイルに関連しています。コンストラクターでの例外の処理は適切に定義されており、完全に構築されたローカル変数およびメンバーに対してデストラクタが呼び出されます。つまり、慣用的なC ++コードに問題はないはずです。スタイルルールはとにかく持続しますが、通常は問題ではありません。すべての初期化をコンストラクターで行う必要はなく、特にそのコンストラクターである必要はありません。
これは、コンストラクターが定義済みの有効な状態を設定するためにできる限り最小限のことを行う必要があるという一般的なスタイルの規則です。初期化がより複雑な場合は、コンストラクタの外部で処理する必要があります。コンストラクターが設定できる初期化するための安価な値がない場合は、クラスによって適用される不変式を弱めて、それを追加する必要があります。たとえば、管理するクラスにストレージを割り当てるのが高すぎる場合は、nullのような特別な場合の状態が問題を引き起こすことはないため、未割り当てのnull状態を追加します。エヘム。
一般的ではありますが、確かにこの極端な形では絶対的とはほど遠いものです。特に、私の皮肉が示すように、私は、不変条件を弱めることはほとんど常に高すぎると言うキャンプにいます。ただし、スタイルルールの背後には理由があり、最小限のコンストラクターと強力な不変式の両方を持つ方法があります。
理由は、特に例外に直面した場合の自動デストラクタのクリーンアップに関連しています。基本的に、コンパイラがデストラクタを呼び出す責任を負うようになるとき、明確に定義されたポイントがなければなりません。まだコンストラクター呼び出しを行っている間は、オブジェクトは必ずしも完全に構築されているとは限らないため、そのオブジェクトのデストラクターを呼び出すことは無効です。したがって、オブジェクトを破棄する責任は、コンストラクターが正常に完了したときにのみコンパイラーに転送されます。これはRAII(Resource Allocation Is Initialization)として知られ、実際には最良の名前ではありません。
コンストラクター内で例外がスローされた場合、部分的に構築されたものはすべて、通常はで明示的にクリーンアップする必要がありますtry .. catch
。
ただし、既に正常に構築されたオブジェクトのコンポーネントは、すでにコンパイラーの責任です。これは、実際には大した問題ではないことを意味します。例えば
classname (args) : base1 (args), member2 (args), member3 (args)
{
}
このコンストラクターの本体は空です。base1
、member2
およびのコンストラクタmember3
が例外セーフである限り、心配する必要はありません。たとえば、throwのコンストラクターはmember2
、そのコンストラクター自体をクリーンアップする責任があります。ベースbase1
はすでに完全に構築されているため、デストラクタが自動的に呼び出されます。member3
部分的に構築されることさえなかったので、クリーンアップは必要ありません。
本体がある場合でも、例外がスローされる前に完全に構築されたローカル変数は、他の関数と同様に自動的に破棄されます。生のポインターをジャグリングする、または何らかの種類の暗黙的な状態(他の場所に格納されている)を「所有」するコンストラクター本体-通常、開始/取得関数呼び出しは終了/解放呼び出しと一致する必要があることを意味します-しかし、そこに本当の問題がありますクラスを介してリソースを適切に管理できません。たとえばunique_ptr
、コンストラクターで生のポインターを置き換えたunique_ptr
場合、必要に応じてデストラクタが自動的に呼び出されます。
do-the-minimumコンストラクターを好む理由は他にもあります。1つは、単にスタイルルールが存在するためです。多くの人は、コンストラクター呼び出しは安価であると考えています。強力な不変式を保持する1つの方法は、代わりに弱化された不変式を持ち、(潜在的に多くの)通常のメンバー関数呼び出しを使用して必要な初期値を設定する別個のファクトリー/ビルダークラスを用意することです。必要な初期状態が得られたら、そのオブジェクトを引数として、強い不変条件を持つクラスのコンストラクターに渡します。これは、弱不変オブジェクトの「内臓を盗む」ことができます-意味論を移動します-これは安価な(そして通常noexcept
)操作です。
そしてもちろんmake_whatever ()
、それを関数でラップすることができるので、その関数の呼び出し元は、弱化された不変クラスのインスタンスを見る必要がありません。