2010-12-29 13 views
7

しばらくして、私は何年も持っていたコーディングパターンに気付き、それが私を緊張させます。私は特定の問題はありませんが、なぜ私がそのパターンを採用したのかについても十分に覚えていないし、その一部のパターンはいくつかのアンチパターンと一致するようです。これは最近私のコードのいくつかが例外をどのように使っているのか私には起こりました。私はC++のcatch節、例外クラスのファミリ、および破棄を使用していますか?

気になることは、 "参照によって"例外をキャッチし、パラメータを関数にどのように扱うかと同じように扱う場合です。これを行う理由の1つは、例外クラスの継承階層を持つことができ、アプリケーションに応じてより一般的な、またはより正確なキャッチタイプを指定できることです。例えば、私はp_Exception経由...

class widget_error {}; 
class widget_error_all_wibbly : public widget_error {}; 
class widget_error_all_wobbly : public widget_error {}; 

void wibbly_widget() 
{ 
    throw widget_error_all_wibbly(); 
} 

void wobbly_widget() 
{ 
    throw widget_error_all_wobbly(); 
} 

void call_unknown_widget (void (*p_widget)()) 
{ 
    try 
    { 
    p_widget(); 
    } 
    catch (const widget_error &p_exception) 
    { 
    // Catches either widget_error_all_wibbly or 
    // widget_error_all_wobbly, or a plain widget_error if that 
    // is ever thrown by anything. 
    } 
} 

これは(私は関数内(スローの一部として)クラスのインスタンスが構築されることに気付きましたので、今私を心配されますが、参照されている定義できますキャッチ節 "パラメータ")を呼び出すことができます。これは通常、アンチパターンです - ローカル変数への参照またはポインタ、または関数内で作成された一時的なものですが、関数が終了すると渡されます。通常、ローカル変数/ temporaryが破棄され、関数が終了するとき。

いくつかの簡単なテストでは、スロー句で作成されたインスタンスは、関数が終了すると破棄されず、それを処理するcatch節が完了すると破棄されます。ただし、catchブロックが再スローされない限りこの場合、次のcatchブロックがこのジョブを行います。

私が残っている緊張感は、1つまたは2つのコンパイラでテストを実行すると、標準が何を示すのかという証拠ではなく、私の経験から言えば、言語が保証するものとは異なることが多いからです。

このように、例外を処理する(参照型を使用してキャッチする)このパターンは安全ですか?または、私は他の何かをする必要がありますか...

  • ヒープ割り当てインスタンスへのポインタをキャッチ(明示的に削除)します。
  • スマートポインタクラスを使用していますか?
  • "値渡し" catch句を使用し、1つのcatch句を持つ階層から例外クラスをキャッチできないことを受け入れるか?
  • 私が考えなかったことは何ですか?
+2

[仮想継承を使用](http://www.boost.org/community/error_handling.html)。 – ybungalobill

+1

@ybungalobill - 私はそれが冗談だと​​思ったが、私はそのリンクを読んだ。興味深い点。 – Steve314

答えて

9

これは問題ありません。実際には、定数参照によって例外をキャッチするのが良い(そしてポインタをキャッチするのは悪い)。値をキャッチすると不要なコピーが作成されます。コンパイラは、例外(とその破壊)を適切に処理するのに十分なほどスマートです - キャッチブロックの外で例外参照を使用しようとしないでください;-)

実際に、私はしばしば私を継承しますstd :: runtime_error(std :: exceptionから継承したもの)の階層。その後、私は.what()を使用することができ、より多くの例外を処理する間により少ないキャッチブロックを使用します。

+0

+1を回すと便利な回答が得られます。私は最も役に立つものが引き裂かれていますが、ついにこれを受け入れることに決めました。 – Steve314

6

このパターンは間違いなく安全です。

スローされたオブジェクトの存続期間を延長する特別な規則があります。効果的には、処理されている限り存在し、それを処理する最後のcatchブロックの最後まで存在することが保証されます。

たとえば、std::exceptionからカスタム例外を派生させ、そのメンバ関数what()をオーバーライドし、参照によってキャッチすると、1つのcatch句でさまざまな例外からのエラーメッセージを出力できます。

4

はい。ここまでは順調ですね。

私は個人的にすべての例外カルセの基盤としてstd :: runtime_errorを使用します。エラーメッセージなどを処理します。

さらに例外を宣言する必要はありません。実際に捕らえられて修正されるものに対してのみ例外を定義してください。捕らえられたり修正されなかったりするものには、より一般的な例外を使用してください。

例:ライブラリAを開発した場合、std :: runtime_errorから派生したAExceptionが発生します。この例外は、ライブラリからのすべての一般的な例外に対して使用されます。ライブラリーのユーザーが実際にキャッチして例外を修正(または軽減)することができる特定の例外については、AExceptionから派生した特定の例外を作成します(ただし、例外で実行できるものがある場合のみ)。

関連する問題