19

別の質問の誰かが、他の方法では処理されていないすべての例外をキャプチャするために使用することを提案しました-全体をブロックでcatch(...)囲むことにより、予期しない/予期しない例外。main()try{}catch(...){}

プログラムのデバッグにかかる​​時間を大幅に節約し、少なくとも何が起こったかのヒントを残すことができる興味深いアイデアのように思えます。

質問の本質は、その方法でどのような情報を回復できるか(私が残したデバッググローバルを除く)、そしてそれをどのように回復するか(キャッチが呼び出されたときにアクセスして認識する方法)です。

また、どのような警告がそれに関連しています。特に:

  • 後で発芽するスレッドでうまく機能しますか?
  • segfaultsの処理を中断しませんか(シグナルとして他の場所でキャプチャされます)
  • 予想される例外を処理するために存在する、必然的に内部にネストされた他のtry ... catchブロックには影響しませんか?
4

6 に答える 6

15

はい、それは良い考えです。

例外をメインからエスケープさせると、アプリケーションがシャットダウンされる前にスタックが巻き戻されるのは、実装で定義された天気です。したがって、私の意見では、メインですべての例外をキャッチすることが不可欠です。

問題は、それらをどうするかということです。
一部のOS(MSおよびSEを参照)は、いくつかの追加のデバッグ機能を提供するため、例外をキャッチした後で例外を再スローするだけで便利です(とにかくスタックが巻き戻されているため)。

int main()
{
    try
    {
        /// All real code
    }
    // I see little point in catching other exceptions at this point 
    // (apart from better logging maybe). If the exception could have been caught
    // and fixed you should have done it before here.

    catch(std::exception const& e)
    {
         // Log e.what() Slightly better error message than ...
         throw;
    }
    catch(...)   // Catch all exceptions. Force the stack to unwind correctly.
    {
        // You may want to log something it seems polite.
        throw;  // Re-throw the exception so OS gives you a debug opportunity.
    }
}
  • 後で発芽するスレッドでうまく機能しますか?

スレッドには影響しないはずです。通常、子スレッドを手動で結合して、それらが終了したことを確認する必要があります。メイン出口が明確に定義されていない場合に子スレッドに何が起こるかについての正確な詳細(ドキュメントを読んでください)が、通常、すべての子スレッドは即座に死にます(スタックの巻き戻しを伴わない厄介で恐ろしい死)。

子スレッドの例外について話している場合。繰り返しますが、これは明確に定義されていません(したがって、ドキュメントを読んでください)が、スレッドが例外を介して終了する場合(つまり、スレッドを開始するために使用される関数が例外のために終了し、戻りではない場合)、これにより通常、アプリケーションが終了します(同じ影響上記のように)。したがって、すべての例外がスレッドを終了するのを停止することが常に最善です。

  • segfaultsの処理を中断しませんか(シグナルとして他の場所でキャプチャされます)

シグナルは、例外処理メカニズムの影響を受けません。
ただし、シグナルハンドラーはスタックに奇妙な構造を配置する可能性があるため(通常のコードに戻るために)、シグナルハンドラー内から例外をスローすることはお勧めできません。これは、予期しない結果を引き起こす可能性があるためです(また、移植性がないことは間違いありません)。 )。

  • 予想される例外を処理するために存在する、必然的に内部にネストされた他のtry ... catchブロックには影響しませんか?

他のハンドラーには影響しないはずです。

于 2010-02-02T15:02:03.163 に答える
5

私が覚えている限り、catch(...)Win32ではSEH例外もキャッチしますが、これは望ましくありません。SEH例外が発生した場合は、非常に恐ろしいことが起こったため(主にアクセス違反)、環境を信頼できなくなります。できることのほとんどすべてが別のSEH例外で失敗する可能性があるため、試す価値すらありません。さらに、一部のSEH例外は、システムによってキャッチされることを目的としています。これについて詳しくはこちらをご覧ください

したがって、私のアドバイスは、std::exceptionすべての例外に基本例外クラス(たとえば)を使用し、そのタイプだけを「キャッチオール」でキャッチすることです。他の種類の例外は定義上不明であるため、コードを準備して他の種類の例外を処理することはできません。

于 2010-02-02T12:33:21.307 に答える
4

グローバルなtrycatchブロックは、ユーザーに不快なメッセージを表示しないようにするために、実動システムに役立ちます。開発中は、それを避けるのが最善だと思います。

あなたの質問について:

  • グローバルcatchブロックは、別のスレッドで例外をキャッチしないと思います。各スレッドには独自のスタックスペースがあります。
  • これについてはよくわかりません。
  • ネストされたtry...catchブロックは影響を受けず、通常どおり実行されます。例外は、tryブロックが見つかるまで、スタックを伝播します。
于 2010-02-02T10:01:08.753 に答える
2

.netアプリケーションを作成している場合は、私が使用しているソリューションを試すことができます。これにより、未処理のすべての例外がキャプチャされます。私は通常#ifndef DEBUG、デバッガーを使用していないときにのみ、本番コードのコード(を使用)を有効にします。

kgiannakakisが他のスレッドでは例外をキャプチャできないと述べているので、指摘する価値がありますが、それらのスレッドで同じtry-catchスキームを使用し、例外をメインスレッドにポストバックして、それらを再スローして取得できます。何がうまくいかなかったかのフルスタックトラック。

于 2010-02-02T10:02:12.913 に答える
1

そしてそれを回復する方法(キャッチが呼び出されたものにアクセスして認識する方法)

スローされた例外のタイプを回復する方法を意味する場合は、フォールバックする前に、特定のタイプのキャッチブロックをチェーンすることができます(より具体的なものからより一般的なものに進みます)catch (...)

try {
   ...
} catch (const SomeCustomException& e) {
   ...
} catch (const std::bad_alloc& e) {
   ...
} catch (const std::runtime_error& e) {
   // Show some diagnosic for generic runtime errors...
} catch (const std::exception& e) {
   // Show some diagnosic for any other unhandled std::exceptions...
} catch (...) {
   // Fallback for unknown errors.
   // Possibly rethrow or omit this if you think the OS can do something with it.
}

mainこれを複数の場所で行っていて、コードを統合したい場合(おそらく、別々のプログラム用の複数の関数)、次の関数を記述できることに注意してください。

void MyExceptionHandler() {
   try {
      throw; // Rethrow the last exception.
   } catch (const SomeCustomException& e) {
      ...
   }
   ...
}

int main(int argc, char** argv) {
   try {
      ...
   } catch (...) {
      MyExceptionHandler();
   }
}
于 2010-02-02T10:17:44.783 に答える
0

クエリできるタイプ/オブジェクト情報がないため、キャッチオールはそれほど有用ではありません。ただし、アプリケーションによって発生するすべての例外が単一の基本オブジェクトから派生していることを確認できる場合は、基本例外にcatchブロックを使用できます。しかし、それは万能ではありません。

于 2010-02-02T10:22:24.747 に答える