あなたは2種類の失敗を区別するのは正しいです、確かにそれらは微妙に異なります。
コンストラクターの障害:ファイルが存在しない、読み取り権限がない、無効/解析できないデータが含まれているなどの可能性があります。
例外をスローするだけです。ハーフビルドオブジェクトは、バグの多いプログラムへの最短の方法です。
クラスには、コンストラクターが確立し、すべてのメソッドが維持する不変条件が必要です。コンストラクターが不変条件を確立できない場合、オブジェクトは使用できません。C++でこれを報告する最良の方法は、言語がハーフビルドオブジェクトが使用されないように例外をスローすることです。
無効な状態が必要である可能性があると人々が提案した場合は、単一責任の原則を思い出してください。クラスにはすでに特定の責任(不変)があり、さらに多くを希望する場合は、オプションを提供するための専用のクラスにカプセル化できます。私の頭から離れて、そして両方とも優れた選択肢です。boost::optional
std::unique_ptr
通常の方法での失敗:ファイルがすでに存在している、書き込みアクセス権がない、円グラフを作成するために利用できる販売データが少なすぎるなどの可能性があります。
残念ながら、次の2つのケースを区別できませんでした。
- インスタンスを読み取るだけのメソッド
- インスタンスも変更するメソッド
すべての方法で、エラー報告戦略を選択する必要があります。私のアドバイスは、例外は例外的であるということです。障害が例外的であると見なされる場合(99.99%の確率でネットワークリンクがダウンしている場合)、例外は問題ありません。一方、失敗が予想される場合は、通常、find
メソッドなどの入力、または場合write
によっては指定されたファイルへのメソッドに応じて、ユーザーに適切に対応する機会を与える必要があります。
例外が除外された後、少なくとも2つの方法が残っています。
- 操作がうまくいったかどうかを示すコード(
bool
、 )を返すenum
- 問題が発生した場合に呼び出されるエラーポリシーを提供するようにユーザーに求める
エラーポリシーは、enum
(スキップ、再試行-1回、スロー)のように単純な場合もあれば、さまざまな方法で本格的に実行される場合のように複雑な場合もありStrategy
ます。
さらに、あなたのメソッドにエラー報告メカニズムが1つしかない可能性があるとは誰も言いません。たとえば、次のように選択できます。
- ファイルがすでに存在する場合にエラーポリシーを呼び出すには(結局のところ、ユーザー提供、別の名前に切り替えたい場合があります)
- ディスクにアクセスできない場合にスローします(ハードウェアは一般的に機能すると予想されます!)
最後に、これに加えて、インスタンスも変更するメソッドは、コンストラクターが確立した不変条件を維持することを心配する必要があります。メソッドが不変条件を台無しにする可能性がある場合、それはまったく不変条件ではなく、ユーザーはクラスが使用されるたびに恐れて震える必要があります...一般的な知恵は、オブジェクトの変更を開始する前にスローする可能性のあるすべての操作を実行することです。
単純な(しかし非常に簡単な)実装は、コピーとスワップのイディオムです。オブジェクトを内部的にコピーし、コピーに対して操作を実行し、メソッドの最後でコピーの状態を現在のオブジェクトの状態とスワップします。何か問題が発生した場合、コピーは破損し、スタックの巻き戻し中にすぐに破棄され、オブジェクトはそのままになります。
このトピックの詳細については、例外保証についてお読みください。私が説明したのは、データベーストランザクション(すべてまたはまったく)に似た、StrongExceptionGuaranteeメソッドの典型的な実装です。