C ++プログラムはすべての例外をキャッチし、例外が過去のmain()でバブリングするのを防ぎますか?


29

私はかつて、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()、エラーメッセージが出力される可能性はありますが、すぐにエラーが表示されることがあります。




@gnat私の質問はもう少し具体的です。これは、どのような状況でもプログラミング言語での例外処理ではなく、処理できないC ++例外に関するものです。
プラキソライト

マルチスレッドプログラムの場合、事態はより複雑またはよりエキゾチックになります(
wrt

1
用ソフトウェアの連中アリアン5は確かに...彼らは最初の起動時にすべての例外をキャッチしていた希望
エリック・タワーズ

回答:


25

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


12
あなたが本当にデストラクタの呼び出しによって復元されるために必要な、あなたは漬物にしていることをいくつかのリソースを持っている場合は... =>(残念ながら)C ++は非常にクラッシュが発生しやすいですし、それはOSが殺すために決めるかもしれないことを言及せずだということを考えるとプログラム(たとえばUnixのOOMキラー)、プログラム(およびその環境)は、クラッシュをサポートするように調整する必要があります。
マチューM.

なつみ デストラクタは、クラッシュ時にも発生するリソースのクリーンアップに適した場所ではないと言っていますか?
プラクセオリック

6
@Praxeolitic:すべてのクラッシュがスタックを巻き戻すとはstd::abort限りません。たとえば、そうではないため、失敗したアサーションもスタックを巻き戻しません。最近のOSでは、OS自体がプロセスIDに関連付けられている多くのリソース(メモリ、ファイルハンドルなど)をクリーンアップすることにも注意する価値があります。最後に、「Defense in Depth」もほのめかしていました。他のすべてのプロセスがバグに耐えることを期待するのは信頼できません。それ...
マシューM.

3
@Praxeoliticいいえ、停電中にソフトウェアがデータを破損ないようにする必要があります。そして、それを管理できれば、未処理の例外の後にデータが破損しないように管理することもできます。
user253751

1
@Praxeolitic:実際、これは存在します。WM_POWERBROADCASTメッセージを聞きたいと思うでしょう。これは、コンピューターがバッテリー駆動の場合にのみ機能します(ラップトップまたはUPSを使用している場合)。
ブライアン

28

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

長期間使用することや広く配布することを意図していないプログラムの場合、OSが決定した方法にかかわらず、予期しないエラーが報告されることは許容できます(たとえば、Windowsでの面内エラーダイアログの表示) )。

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


残すC ++例外のデフォルトの動作はmain() 、OSと関係がありますか?OSはC ++をまったく知らない可能性があります。私の推測では、コンパイラがプログラムのどこかに挿入するコードによって決定されると思いました。
プラクセオリック

5
@Praxeolitic:さらに、OSが規約を設定し、プログラムが予期せず終了した場合にコンパイラがこれらの規約を満たすコードを生成します。結論としては、合理的に可能な限り、プログラムの予期しない終了を回避する必要があるということです。
バートヴァンインゲンシェナウ

std C ++のスコープ内でのみ制御を失います。そのような「クラッシュ」を処理する実装固有の方法が利用可能であるべきです。C ++は通常、真空状態では実行されません。
マーティンBa

その対面エラーダイアログは、その価値に応じてレジストリでオン/オフを構成できますが、これを行うにはレジストリの制御が必要になります。また、ほとんどのプログラムはキオスクモードで実行されていませんOS)。
-PerryC

11

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


技術的な迂回...

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

  • スタックが巻き戻されるかどうかに関係なく定義された実装です
  • std::terminate デフォルトで中止される
  • 環境の設定に応じて、アボートはクラッシュレポートを残す場合と残さない場合があります

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


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

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

本番プログラムでは、これを指定する必要があり、仕様に従う必要があります(変更される可能性があると主張する場合もあります)。

技術者(あなた、チームメイト)のみが使用するプログラムをすばやくまとめたい場合は、どちらでも構いません。クラッシュさせ、環境をセットアップしてレポートを取得するかどうかをお勧めします。


1
この。決定要因はwrtです。基本的にC ++の範囲外です。
マーティンBa

4

キャッチした例外により、素敵なエラーメッセージを出力したり、エラーから回復しようとしたりすることができます(アプリケーションを再起動するだけの場合もあります)。

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

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


4

中断する必要があるとわかった瞬間に、先に進み、std::terminateそれ以上の損害を抑えるために電話をかけます。

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

システムが単独でエラーを行うよりも安全にエラーを報告/記録できる場合は、先に進みます。
しかし、そうしている間、不注意で事態を悪化させないように本当に気をつけてください。

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


1

ほとんどの場合、正常にクラッシュするのは良いことですが、トレードオフがあります。時々、クラッシュするのは良いことです。私は大部分のデバッグを主に​​考えていることを言及する必要があります。単純なプログラムの場合-これはまだ有用かもしれませんが、非常に複雑なプログラム(または相互作用するいくつかの複雑なプログラム)ほど有用ではありません。

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

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

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

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


-6

最終的に、例外がmain()を超えてバブルアップすると、アプリケーションがクラッシュします。私の考えでは、アプリは決してクラッシュしません。1つの場所でアプリをクラッシュしても問題ない場合は、どこでもできませんか?なぜ例外処理にまったく煩わされるのですか?(皮肉、これを実際に示唆していない...)

グローバルなtry / catchを使用して、回復不能なエラーが発生し、IT部門のbobにそれまたは同様のものについて電子メールで通知する必要があることをユーザーに知らせるエレガントなメッセージを出力する場合がありますが、クラッシュは完全に専門的ではなく受け入れられません。防止するのは簡単で、何が起こったのか、また二度と起こらないように修正する方法をユーザーに知らせることができます。

クラッシュは厳密にアマチュアの時間です。


8
だから、すべてが正常に動作しているふりをして、代わりにすべての永続的なストレージをちんぷんかんぷんに上書きしますか?
デデュプリケーター

1
@Deduplicator:いいえ:例外をいつでもキャッチして処理できます。
ジョルジオ

5
あなたがそれを処理する方法を知っているなら、あなたはおそらくあなたが起きるまでにずっとそれを処理するでしょうmain。あなたがそれを処理する方法を知らないなら、あなたがするふりは明らかに本当に恐ろしいバグです。
デュプリケータ

8
しかし、クラッシュは完全にプロフェッショナルではなく、容認できません =>役に立たない機能に時間を費やすことはプロフェッショナルではありません。より経済的です。
マチューM.

Matthieu M.エラーを記録し、開いているファイルを保存し、画面にわかりやすいメッセージを表示するのに本当にそんなに労力がかかる場合、私は何を言うべきかわかりません。優雅に失敗するのは役に立たないと思うなら、おそらくあなたのコードの技術サポートをしている人と話をするべきです。
ロジャーヒル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.