2011-12-21 3 views
3

次のコードスニペットを考えてみましょう:標準から例外の有効期間はネストされたハンドラによって影響を受けますか?

struct ExceptionBase : virtual std::exception{}; 
struct SomeSpecificError : virtual ExceptionBase{}; 
struct SomeOtherError : virtual ExceptionBase{}; 

void MightThrow(); 
void HandleException(); 
void ReportError(); 

int main() 
{ 
    try 
    { 
    MightThrow(); 
    } 
    catch(...) 
    { 
    HandleException(); 
    } 
} 

void MightThrow() 
{ 
    throw SomeSpecificError(); 
} 

void HandleException() 
{ 
    try 
    { 
    throw; 
    } 
    catch(ExceptionBase const &) 
    { 
    // common error processing 
    } 

    try 
    { 
    throw; 
    } 
    catch(SomeSpecificError const &) 
    { 
    // specific error processing 
    } 
    catch(SomeOtherError const &) 
    { 
    // other error processing 
    } 

    ReportError(); 
} 

void ReportError() 
{ 
} 

15.1.4項を教えてくれる:

スローされた例外の一時的なコピーのためのメモリが指定されていない方法で 割り当てられ、 3.7.3.1に記載されている場合を除く。 例外のためにハンドラが実行されている限り、 のテンポラリは持続します。特に、ハンドラが throwを実行して終了した場合、同一の 例外の別のハンドラに制御を渡すので、一時的に残ります。 例外のために実行された最後のハンドラが の場合、throw以外の手段で終了します。 一時オブジェクトが破棄され、が実装され、一時オブジェクトのメモリが に割り当て解除される可能性があります。そのような割り振り解除は、指定されていない方法で で行われます。破棄は、 ハンドラの例外宣言で宣言されたオブジェクトの破棄の直後に発生します。

mainのハンドラを「最後のハンドラ」として表示するのは正しいですか?したがって、現在の例外オブジェクトの破壊を引き起こさずに、HandleExceptionに任意の数の再スローとキャッチが許可されますか?

+4

¤「main」のハンドラが最後のものです。そして、はい、あなたは、あなたが望むように何度も例外を再スローして再カウントすることができます。しかし、それは良い考えではありません。代わりに、ハンドラに(1)純粋な例外変換、または(2)純粋なロギングと終了を行わせます。このハンドラコードは、当然のことながら、失敗に対処する知識を持っていません。 Cheer&hth。、 –

+0

@Alfありがとう。小さなコードサンプルを投稿しようと努力する中で、いくつかの重要な細部を省いたようです。実際、ExceptionBaseはboost :: exception(コンテキストデータの多くの共通部分が抽出されます)から派生しています。さらに、 'main'は実際には任意の数のCOMメソッドの1つで、適切なHRESULTコードを返す前にエラーが記録されます(一般的なコンテキストデータとエラー固有のコンテキストデータの両方で)。しかしどちらにせよ、あなたは私の質問に答えました。 –

答えて

0

アムは、私がメインで、ハンドラを表示するには修正「最後のハンドラ?」

はい、あります。

ので、再スローのと漁獲量の任意の数は現在の例外オブジェクトの破壊を引き起こすことなく、HandleExceptionで許可されていますか?

はい。最終的に未処理の例外オブジェクトは、コンパイラ生成コードによって破棄されます。メモリリークは発生しません。

HandleException()に再スローするのは良いことではありません。代わりに 1.特定の処理を要求する例外タイプにキャッチを書き込みます。 2. dynamic_castを使用して例外処理をグループ化できます。基本例外タイプをキャッチし、それを派生した例外クラスのいずれかにダウンキャストしようとします。しかし、dynamic_castは良い習慣ではありません。だから、第1の解決策を使う方が良いです。

それは次のようにあなたのコードを書き換える方が良いでしょう。これまでに投稿されたコメントと回答のため

struct ExceptionBase : virtual std::exception{}; 
struct SomeSpecificError : virtual ExceptionBase{}; 
struct SomeOtherError : virtual ExceptionBase{}; 

void MightThrow(); 
void HandleExceptionBase(); 

int main() 
{ 
    try 
    { 
    MightThrow(); 
    } 
    catch (SomeOtherError &error) { 
    // first common code 
    HandleExceptionBase(); 
    // react on this exception correctly 
    // specific code 
    } 
    catch (SomeSpecificError &error) { 
    // first common code 
    HandleExceptionBase(); 
    // react on this exception correctly 
    // specific code 
    } 
    catch (ExceptionBase &error) { 
    HandleExceptionBase(); 
    // finally catch anything derived from base class 
    // react on this exception correctly 
    } 
    catch(...) { 
    // react on any other exception except 3 listed above 
    } 
} 

void MightThrow() 
{ 
    throw SomeSpecificError(); 
} 

void HandleExceptionBase() { 
    // base exception handler 
} 
+0

お返事ありがとうございます。しかし残念ながら、私が尋ねた質問には答えません。あなたの答えを自由に編集してください。私はそれをupvoteすることができます。また、 'SomeOtherError'か' SomeSpecificError'のいずれかがキャッチされた場合、 'ExceptionBase'のハンドラが実行されないという点で、コードの動作が元のものと異なることに注意してください。 –

0

感謝。私は私が探しているものを見たことがないので、私はan answer provided by ascheplerの情報をフォローアップの質問に追加します。

15.3p7:ハンドラは、catch節の仮パラメータ(ある場合)の初期化が完了したときにアクティブと見なされます。 ... ハンドラは、catch節が終了したとき、またはスローによって入力された後に std :: unexpected()が終了したときにアクティブであるとはもはや考えられません。

15。3p8:まだアクティブになっている最も最近アクティブ化されたハンドラを持つ例外は、現在処理されている例外と呼ばれます。

私は標準の言語がここに非常に明確であり、mainが実際に最後ハンドラだと思います。したがって、例外の存続期間はネストされたハンドラの影響を受けません。

関連する問題