「例外を使用する」と「エラーコードを使用する」は、例が示唆するほど明確ではありません。
プログラム フローのエラー コードを使用します。予期されるエラーが発生した場合は、例外をスローしないでください。たとえば、ファイルを読み取っている場合、「ファイルが見つかりません」、「ファイルがロックされています」の例外をスローする場合があります。ただし、 「ファイルの終わり」に対してスローしないでください。
そうした場合、単純なループを記述することはできず、常にコードを例外ハンドラーでラップすることになります。また、例外は非常に遅いことを忘れないでください。これは、大規模なマルチスレッド サーバーでは特に重要です。(デスクトップ アプリケーションではそれほど重要ではありません)。
次に、例外階層には十分注意してください。Exception
クラスを持っていて、そこからを派生させてNetException
からSMTPException
、SMTP クラスを作成しても問題ないと思うかもしれません。ただし、基本クラスに汎用データを保持しない限り、その階層内のすべての種類の例外を常にキャッチする必要があります。たとえば、SMTP エラーの理由をSMTPException
クラスに入れる場合は、それをキャッチする必要があります。型だけをキャッチすると、メンバーException
にアクセスできなくなります。SMTPException
この問題の適切な回避策は、基本例外クラスに文字列と int メンバーを持ち、派生型であってもそれらのみを使用することです。残念ながらstd::exception
、文字列のみを提供しています:(
これを行うと、特に基本クラスの型を常にキャッチするため、単一の例外型のみを使用することを意味すると言う人もいます。
例外を使用する場合は、エラー コードの場合よりも多くのデータを入力する必要があります。エラーが発生した場合は、すぐに処理する必要があります。そうしないと、コード内で失われてしまいます。例外を除いて、ロディの例のように、投げられた場所から何層も離れた場所で捕まる可能性があります。DoC
が呼び出され、 from で 2 レベルの例外を取得しますDoA
。のコードに固有のエラーを指定しない限りDoA
、関数からスローされたと考えることができますDoB
。(単純な例ですが、呼び出しスタックの何層も下のレベルで例外が処理されるコードを見てきました。デバッグするのは不可能でした。これは特にOOプログラムに当てはまります)
うまくいけば、私はあなたに考えるのに十分なものを与えました. 問題の単純な真実は、エラー処理においてスタイルは何の意味も持たず、実用性がすべてであるということです。エラーが発生する可能性のあるすべての場所にログステートメントを配置する必要がある場合は、そうしてください。洗練された例外階層を持っているか、コードに例外ハンドラーを散らかしているよりも、コードのどこで問題が発生したか (およびどのデータが処理されたか) を確認できることの方がはるかに重要です。エラーを簡単に追跡できない場合、エラー処理コードは役に立ちません。
例外は良いです、それらを使用してください。しかし、自分が何をしているのかよく考えて、それらを誤用したり使いすぎたりしないでください。誤用された例外は、エラー処理がまったくないよりも悪いことです (クラッシュ ダンプを取得し、処理されていない例外を表示して、数秒でエラーを見つけることができるためです。食べられて無視される例外があると、詰め込まれます)。
私は長年にわたって、デバッグの最大の助けがロギングであることを発見しました。ログを書き、たくさんのログを書きます。