web-dev-qa-db-ja.com

C ++プログラムはすべての例外をキャッチし、例外がmain()を超えてバブリングしないようにする必要がありますか?

私はかつて、C++プログラムが最終的にすべての例外をキャッチするべきだとアドバイスされました。当時与えられた推論は基本的に、main()の外で例外が発生することを許可するプログラムが奇妙なゾンビ状態に入るというものでした。私はこれを数年前に言われました、そして振り返ってみると、観察された現象は問題のプロジェクトからの非常に大きなコアダンプの長い生成によるものであったと思います。

当時、これは奇妙に思えましたが説得力があります。 C++がすべての例外をキャッチしなかったためにプログラマーを「罰する」べきであるというのはまったく無意味でしたが、私の前の証拠はこれを裏付けているようです。問題のプロジェクトの場合、キャッチされない例外をスローしたプログラムは、奇妙なゾンビ状態に入ったようです。あるいは、私が原因を疑っているように、不要なコアダンプの最中のプロセスを停止するのは非常に困難です。

(なぜこれが当時はもっと明白でなかったのかと思っている人のために:プロジェクトは、あらゆる種類のaborted (core dumped)メッセージを効果的に覆い隠した、複数のプロセスから複数のファイルに大量の出力を生成しました。コアダンプの詳細な調査は重要なデバッグ手法ではなかったため、コアダンプはあまり考慮されていませんでした。通常、プログラムの問題は、長期にわたるプログラムによって多くのイベントから蓄積された状態に依存せず、むしろ存続期間の短いプログラム(<1時間)であるため、デバッグビルドまたはデバッガーから同じ入力を使用してプログラムを再実行して詳細を取得する方が現実的でした。)

現在、例外がmain()を離れないようにする目的でのみ例外をキャッチすることの主な利点または欠点があるかどうかはわかりません。

main()を超えて例外が発生することを許可することで考えられる小さな利点は、std::exception::what()の結果がターミナルに出力されることです(少なくともLinuxのgccコンパイル済みプログラムでは)。一方、これは、std::exceptionから派生したすべての例外をキャッチしてstd::exception::what()の結果を出力することで、簡単に実現できます。 std::exceptionの場合、メッセージを印刷するためには、main()を離れる前にキャッチする必要があります

例外がmain()を超えて例外が発生することを許可するために考えられる適度な欠点は、不要なコアダンプが生成される可能性があることです。大量のメモリを使用するプロセスの場合、これは非常に煩わしい場合があり、プログラムからコアダンプ動作を制御するにはOS固有の関数呼び出しが必要です。一方、コアダンプと終了が必要な場合は、代わりにstd::abort()を呼び出していつでもこれを実現でき、std::exit()を呼び出していつでもコアダンプなしの終了を実現できます。 。

事例として、クラッシュ時に広範囲に分散したプログラムによって出力されるデフォルトのwhat(): ...メッセージを見たことがないと思います。

もしあれば、C++の例外がmain()を超えて泡立つことを許可することに対する賛成または反対の強力な議論は何ですか?

編集:このサイトには、例外処理に関する一般的な質問がたくさんあります。私の質問は特に、処理できないC++例外についてであり、main()に到達しました。おそらくエラーメッセージが出力される可能性がありますが、それは即座に表示される停止エラーです。

29
Praxeolitic

例外をmainを通過させる場合の1つの問題は、プログラムがstd::terminateの呼び出しで終了することです。デフォルトの動作はstd::abortの呼び出しです。 実装定義のみです。terminateを呼び出す前にスタックの巻き戻しが行われる場合、単一のデストラクタを呼び出さずにプログラムを終了できます。デストラクタ呼び出しによって本当に復元する必要のあるリソースがある場合は、漬け物になっています...

26
erlc

例外をmainからエスケープさせない主な理由は、そうしないと、ユーザーに問題を報告する方法を制御する可能性がすべて失われるためです。

長期間使用することを意図していない、または広く配布されることを意図していないプログラムの場合、予期しないエラーがOSが決定した方法で報告されても問題ありません(たとえば、Windowsで顔にエラーダイアログが表示される) )。

販売するプログラム、または支持する評判のある組織によって一般に提供されるプログラムの場合、予期しない問題が発生したことを適切な方法で報告し、できるだけ多くを保存することをお勧めします可能な限りユーザーのデータ。ユーザーの半日の作業を失うことなく、予期せずクラッシュすることもありませんが、半ば正常にシャットダウンすることは、一般に、他の方法よりもビジネスの評判にとってはるかに優れています。

TL; DR仕様は何と言っていますか?


技術的な迂回...

例外がスローされ、ハンドラーの準備ができていない場合:

  • スタックがほどかれるかどうかは、実装で定義されます
  • std::terminateが呼び出され、デフォルトで中止されます
  • 環境の設定によっては、中止してもクラッシュレポートが残される場合と残されない場合があります

後者は、非常にまれなバグに役立ちます(それらの再現は時間のかかるプロセスであるため)。


すべての例外をキャッチするかどうかは、最終的には仕様の問題です。

  • ユーザーエラーを報告する方法が指定されていますか? (無効な値、...)
  • 機能エラーを報告する方法が指定されていますか? (ターゲットディレクトリがありません...)
  • 技術的なエラーを報告する方法が指定されていますか? (アサーションの起動、...)

どんなプロダクションプログラムでも、これを指定する必要があり、仕様に従う必要があります(変更される可能性があると主張することもできます)。

技術者(あなた、あなたのチームメイト)だけが使用するプログラムをすばやくまとめるには、どちらでもかまいません。クラッシュさせて、必要に応じてレポートを取得するかどうかを設定することをお勧めします。

11
Matthieu M.

キャッチした例外により、Niceエラーメッセージを出力したり、エラーからの回復を試みたりすることができます(おそらくアプリケーションを再起動するだけです)。

ただし、C++では、例外はスローされたときのプログラムの状態に関する情報を保持しません。キャッチすると、そのような状態はすべて忘れられますが、プログラムをクラッシュさせると、状態は通常まだそこにあり、プログラムダンプから読み取ることができるため、デバッグが容易になります。

したがって、それはトレードオフです。

4
Sebastian Redl

中止する必要があるとわかった瞬間に、先に進んでstd::terminateに電話して、それ以上の損傷を抑制してください。

安全に終了できることがわかっている場合は、代わりにそれを行ってください。例外がキャッチされない場合、スタックの巻き戻しは保証されないため、キャッチして再スローすることを忘れないでください。

システムが単独でエラーを報告するよりも安全にエラーを報告/記録できる場合は、先に進んでください。
しかし、そうしている間、うっかり問題を悪化させないように本当に注意してください。

特定のエラーに依存しますが、回復不能なエラーを検出したときにデータを保存するには遅すぎることがよくあります。
とにかく、プログラムが高速リカバリ用に作成されている場合、通常のシャットダウンであっても、プログラムを強制終了するだけで終了できます。

4
Deduplicator

ほとんどの場合、正常にクラッシュすることは良いことですが、トレードオフがあります。クラッシュするのは良い場合もあります。主に非常に大規模なデバッグについて考えていることを述べておかなければなりません。単純なプログラムの場合-これはまだ便利かもしれませんが、非常に複雑なプログラム(またはいくつかの複雑なプログラムが相互作用する)の場合ほど便利ではありません。

あなたは公共の場でクラッシュしたくありません(ただし、これは避けられないことです-プログラムがクラッシュし、数学的に検証可能な非クラッシュプログラムは、ここでは話していません)。デモの最中にビル・ゲイツのBSODを考えてみてください-悪いですね?それでも、なぜクラッシュしたのか、同じ方法で再度クラッシュしないのかを理解することができます。

未処理の例外でローカルクラッシュダンプを作成するWindowsエラー報告の機能をオンにしました。 (クラッシュした)ビルドに関連付けられたシンボルファイルがあるかどうかは不思議に機能します。興味深いことに、このツールを設定したので、クラッシュしたいmore-それぞれのクラッシュから学ぶからです。その後、バグを修正してクラッシュを減らすことができます。

それで、今のところ、私はプログラムが一番上まで投げてクラッシュすることを望みます。将来的には、すべての例外を優雅に食べたいと思うかもしれませんが、私のためにそれらを機能させることができれば。

興味がある場合は、ここでローカルクラッシュダンプの詳細を確認できます。 ユーザーモードダンプの収集

1
PerryC