1 つの catch ブロックですべての種類の例外をキャッチするにはどうすればよいですか?
-
09-06-2019 - |
質問
C++ では、すべてのタイプの例外を 1 回のキャッチでキャッチしようとしています (例: catch(Exception)
C# で)。どのように行われるのでしょうか?さらに、ゼロ除算の例外はどうやってキャッチできるのでしょうか?
解決
catch (...)
{
// Handle exceptions not covered.
}
重要な考慮事項:
- より良いアプローチは、考えられるすべての例外ではなく、実際に回復できる特定の種類の例外をキャッチすることです。
- catch(...) は、確実に回復できない特定の重大なシステム レベルの例外 (コンパイラによって異なります) もキャッチします。この方法でそれらを捕まえて飲み込み、続行すると、プログラムにさらに深刻な問題が発生する可能性があります。
- コンテキストによっては、例外が再スローされる場合に限り、catch(...) の使用が許容される場合があります。この場合、有用なローカル状態情報をすべてログに記録してから、例外を再スローして上に伝播できるようにします。ただし、次のことをよく読んでください。 RAIIパターン このルートを選択した場合。
他のヒント
あなた しないでください catch (...) を使用したい(すなわち、省略記号でキャッチします)本当に、間違いなく、最も証明できる必要がある場合を除きます。
その理由は、一部のコンパイラ (最も一般的なものを挙げると Visual C++ 6) も、セグメンテーション違反やその他の非常に悪い状態のようなエラーを、catch (...) を使用して喜んで処理できる例外に変換するためです。クラッシュが見られなくなるため、これは非常に悪いことです。
技術的には、はい、ゼロによる除算も捕らえることができます (そのためには「StackOverflow」する必要があります)。しかし、そもそもそのような除算を行うことは避けるべきです。
代わりに、次のことを実行します。
- 実際にどのような種類の例外が予想されるかを知っている場合は、それらの種類だけをキャッチし、それ以上はキャッチしません。
- 自分で例外をスローする必要があり、スローするすべての例外をキャッチする必要がある場合は、(Adam Pierce が提案したように) これらの例外を std::Exception から派生させ、それをキャッチします。
Windows を使用していて、ゼロ除算やアクセス違反などのエラーを処理する必要がある場合は、構造化例外トランスレーターを使用できます。そして、トランスレータ内で C++ 例外をスローできます。
void myTranslator(unsigned code, EXCEPTION_POINTERS*)
{
throw std::exception(<appropriate string here>);
}
_set_se_translator(myTranslator);
コードによってエラーの内容がわかることに注意してください。また、/EHa オプションを使用してコンパイルする必要があります (C/C++ -> コード生成 -> C/C++ 例外を有効にする = SEH 例外ではい)。
それが意味をなさない場合は、[_set_se_translator](http://msdn.microsoft.com/en-us/library/5z4bw5h5(VS.80).aspx)
OS 例外を含むすべての例外をキャッチすることが本当に必要な場合は、コンパイラと OS を確認する必要があります。たとえば、Windows では、おそらく "__try" キーワードか、"try/catch" で SEH 例外をキャッチするコンパイラ スイッチ、またはその両方が使用されていると考えられます。
すべてのカスタム例外クラスを std::Exception から継承させると、単純に std::Exception をキャッチできるようになります。コード例を次に示します。
class WidgetError
: public std::exception
{
public:
WidgetError()
{ }
virtual ~WidgetError() throw()
{ }
virtual const char *what() const throw()
{
return "You got you a widget error!";
}
};
C++ では、標準ではゼロ除算例外が定義されておらず、実装ではゼロ除算例外がスローされない傾向があります。
もちろん使用できます catch (...) { /* code here */ }
, 、しかしそれは本当にあなたが何をしたいかによって異なります。C++ には決定論的なデストラクター (最終処理のようなゴミはありません) があるため、除去したい場合は RAII を使用するのが正しい方法です。
例えば。の代わりに:
void myfunc()
{
void* h = get_handle_that_must_be_released();
try { random_func(h); }
catch (...) { release_object(h); throw; }
release_object(h);
}
次のようなことを実行します。
#include<boost/shared_ptr.hpp>
void my_func()
{
boost::shared_ptr<void> h(get_handle_that_must_be_released(), release_object);
random_func(h.get());
}
boost を使用しない場合は、デストラクターを使用して独自のクラスを作成します。
私の記憶が正しければ (C++ を見てからしばらく経ちました)、次のようにすればうまくいくはずです。
try
{
// some code
}
catch(...)
{
// catch anything
}
そしてちょっとグーグル(http://www.oreillynet.com/pub/a/network/2003/05/05/cpluspocketref.html)私が正しいことを証明しているようです。