web-dev-qa-db-ja.com

例外処理をいつ、どのように使用すればよいですか?

例外処理について読んでいます。例外処理とは何かに関する情報を入手しましたが、いくつか質問があります。

  1. いつ例外をスローしますか?
  2. 例外をスローする代わりに、戻り値を使用してエラーを示すことができますか?
  3. Try-catchブロックですべての機能を保護すると、パフォーマンスが低下しませんか?
  4. 例外処理を使用する場合
  5. そのプロジェクト内のすべての関数にtry-catchブロックが含まれているプロジェクトを見ました(つまり、関数全体のコードはtry-catchブロックに囲まれています)。これは良い習慣ですか?
  6. Try-catchと__try __exceptの違いは何ですか?
73
Umesha MS

これは必読だと思う例外に関する非常に包括的なガイドです:

例外とエラー処理- C++ FAQ または C++ FAQ lite

一般的な経験則として、プログラムが実行を妨げるexternal問題を識別できる場合、例外をスローします。サーバーからデータを受信し、そのデータが無効な場合、例外をスローします。ディスク容量が足りませんか?例外をスローします。宇宙線がデータベースのクエリを妨げていますか?例外をスローします。ただし、独自のプログラム内から無効なデータを取得した場合は、例外をスローしないでください。問題があなた自身の悪いコードに起因する場合、ASSERTを使用してそれを防ぐ方が良いです。ユーザーが問題を処理できるため、プログラムが処理できない問題を特定し、ユーザーについて通知するには例外処理が必要です。ただし、プログラムのバグはユーザーが処理できるものではないため、プログラムがクラッシュしても、「answer_to_life_and_universe_and_everythingの値は42ではありません!これは絶対に発生しない!!!! 11」例外よりも少なくなりません。

メッセージボックスを表示するなど、何か便利なことができる例外をキャッチします。私は、何らかの形でユーザー入力を処理する関数内で一度例外をキャッチすることを好みます。たとえば、ユーザーは「すべてのフナムを全滅させる」ボタンを押します。そして、annihilateAllHunamsClicked()関数内には、「できない」と言うtry ... catchブロックがあります。 hunamkindの消滅は数十個の関数の呼び出しを必要とする複雑な操作ですが、ユーザーにとってはアトミック操作であるため、1回のtry ... catchしかありません-ボタンを1回クリックするだけです。すべての関数の例外チェックは冗長で見苦しいです。

また、RAIIについて十分に理解することはお勧めできません。つまり、初期化されたすべてのデータが自動的に破棄されるようにすることはお勧めできません。そして、それはスタック上で可能な限り初期化することで達成できます。また、ヒープ上で何かを初期化する必要がある場合は、何らかのスマートポインターを使用します。スタックで初期化されたものはすべて、例外がスローされると自動的に破棄されます。 Cスタイルのダムポインターを使用する場合、例外がスローされたときにメモリリークの危険があります。例外時にそれらをクリーンアップする人がいないためです(確かに、Cスタイルポインターをクラスのメンバーとして使用できますが、デストラクタで処理されます)。

80
Septagram

例外は、さまざまな状況で役立ちます。

まず、前提条件を計算するコストが非常に高いため、前提条件が満たされていないことが判明した場合は、計算を実行して例外を発生させて中止するほうがよい関数がいくつかあります。たとえば、特異行列を反転することはできませんが、特異行列であるかどうかを計算するには、非常に高価な行列式を計算します。とにかく関数内で実行する必要があるため、行列とレポートを反転させて「試してください」例外をスローしてもできない場合はエラー。これは基本的に負の前提条件としての例外の使用法です。

次に、コードがすでに複雑で、エラー情報を呼び出しチェーンに渡すことが難しい場合があります。これは、一部にはCとC++のデータ構造モデルが壊れているためです。他のより良い方法がありますが、C++はそれらをサポートしません(Haskellでモナドを使用するなど)。この使用法は基本的に私はそれを気にすることができなかったので例外をスローします:それは正しい方法ではありませんが、実用的です。

次に、例外の主な用途があります。外部の前提条件または不変条件(メモリやディスク領域などの十分なリソースなど)が利用できない場合にレポートするためです。この場合、通常はプログラムまたはその主要なサブセクションを終了しますが、例外は問題に関する情報を送信する良い方法です。 C++例外は、プログラムの継続を妨げるエラーを報告するために設計されました

C++を含むほとんどの最新の言語で使用されている例外処理モデルは、既知破損しています。それは非常に強力です。理論家は現在、完全にオープンな「何かを投げる」モデルや「たぶんキャッチできない」モデルよりも優れたモデルを開発しました。さらに、型情報を使用して例外を分類することはあまり良い考えではありませんでした。

したがって、できる最善のことは、実際のエラーがあり、他に対処する方法がない場合は、例外を控えめにスローしますおよびスローポイントに可能な限り近い例外をキャッチします

12
Yttrill

問題があなた自身の悪いコードに起因する場合、ASSERTを使用してそれを防ぐ方が良いです。ユーザーが問題を処理できるため、プログラムが処理できない問題を特定し、ユーザーについて通知するには例外処理が必要です。ただし、プログラムのバグはユーザーが処理できるものではないため、プログラムのクラッシュはあまりわかりません

受け入れられた答え のこの側面には同意しません。アサートは、例外をスローするよりも実践的ではありません。例外が実行時エラー(または「外部問題」)にのみ適している場合、std::logic_error ために?

論理エラーは、ほとんどの場合、プログラムの継続を妨げる条件の一種です。プログラムが論理構造であり、その論理のドメイン外で条件が発生した場合、どのように続行できますか?あなたがそうするかもしれない間にあなたがたが入力を集め、例外を投げる!

先行技術がないわけではありません。 std::vectorは、名前を1つだけですが、論理エラー例外、つまりstd::out_of_range。標準ライブラリを使用し、標準例外をキャッチするトップレベルハンドラがない場合-what()およびexit(3)-プログラムは突然サイレントに終了します。

Assertマクロは、はるかに弱いガードです。回復はありません。つまり、デバッグビルドを実行していない限り、no executionがあります。 assertマクロは、計算が今日よりも6桁遅い時代に属します。論理エラーをテストするために問題が発生するが、本番環境でそのテストをカウントするときに使用しない場合は、コードに多くの自信がある方が良いでしょう!

標準ライブラリは、論理エラーの例外を提供し、それらを採用しています。理由は次のとおりです。論理エラーが発生し、例外的だからです。 Cがアサーション機能を備えているからといって、例外がジョブをより適切に処理する場合、そのような原始的な(そしておそらくは役に立たない)メカニズムに依存する理由にはなりません。

4
James K. Lowden

これに最適な読み物

例外処理は、過去10年半にわたって多くの話題になっています。ただし、例外を適切に処理する方法に関する一般的なコンセンサスにも関わらず、使用法には格差があります。不適切な例外処理は、見つけやすく、回避しやすく、単純なコード(および開発者)の品質指標です。絶対的なルールは気にかけている、または誇張されているように見えますが、一般的なルールとして、try/catchを使用すべきではありません

http://codebetter.com/karlseguin/2010/01/25/don-t-use-try-catch/

3
Sushan M

1.結果として、または問題の間に例外が発生する可能性がある場合、コードに例外チェックが含まれます。

2. try-catchブロックは、必要な場合にのみ使用します。各try-catchブロックを使用すると、コードの最適化を確実に減らす追加の条件チェックが追加されます。

3. _try_exceptは有効な変数名だと思います...

2
user550830

基本的な違いは:

  1. 1つはエラー処理を行います。
  2. 一つはあなたが自分でやることです。

    • たとえば、0 divide errorを作成できる式があります。 try catch 1.を使用すると、エラーが発生したときに役立ちます。または、if a==0 then..2.が必要です

    • あなたが例外をキャッチしようとしないなら、私はその速いとは思わない、単に単にバイパスする、errorが発生した場合、それは外部ハンドラへのthrewになるだろう。

自分に手渡すことは、問題がそれ以上先に進まないことを意味します。多くの場合、速度に利点がありますが、常にではありません。

Suggest:単純で論理的には自分自身を処理するだけです。

0
pinichi