中止、終了、または終了しますか?


112

これらの3つの違いは何ですか?また、適切に処理できない例外が発生した場合にプログラムを終了するにはどうすればよいですか?


3
これは複製ではなく、いくつかの良い答えを持つサブセット stackoverflow.com/questions/397075/…であり、C ++のタグも付けられています!
エリーケッセルマン2012年

std::abortデストラクタで例外を解決できない場合は、妥当です。
ダニエル

1
詳細についてはについてstd::terminate:アンジェイの優れたC ++のブログでこれらの記事を参照してください。akrzemi1.wordpress.com/2011/09/28/who-calls-stdterminateakrzemi1.wordpress.com/2011/10/05/using-stdterminate
オハッドシュナイダー

回答:


3

私のアドバイスは、それらのいずれも使用しないことです。代わりにcatch、処理できない例外とそこからmain()単純に処理できますreturn。つまり、スタックの巻き戻しが正しく行われ、すべてのデストラクタが呼び出されることが保証されます。言い換えると:

int main() {
    try {
       // your stuff
    }
    catch( ... ) {
       return 1;    // or whatever
    }
}

8
@ニール:基本的に同意しますが、プログラムが処理できない例外は報告して再スローする必要があります。アプリをクラッシュさせます。
John Dibling

13
スタックがほどけるようにするには、常にメインでキャッチする必要があります。しかし、私はキャッチから再び投げるでしょう。一部のOSには、デバッグでコンパイルした場合、デバッグインフラストラクチャを自動的に呼び出す機能があります。
マーティンヨーク

5
トップレベルのハンドラーでもキャッチされない例外は、プロセスをダンプし、Windowsエラー報告、Mac OS Xエラー報告、iPhoneアプリケーションエラーログなどの開発者の注意を引く例外報告をアップロードするシステム報告機能を呼び出す可能性があります。
JBRウィルキンソン

6
@Johnが私にとって意外な理由は、例外が実際にどのように実装されるかを考えると完全に理にかなっていますが、適切なハンドラが見つかるまで(または終了が呼び出された)。そして、漏れやすい抽象化は、しばしば避けられないものですが、遭遇したときは必然的に驚くべきものです。
タイラーマクヘンリー

11
これは質問の半分に答えないため、-1。「[中止、終了、または終了]の違いは何ですか?」これはより良い答えです。stackoverflow.com/ a / 397081/353094また、stackoverflow.com / a / 2820407/353094も素晴らしい答えです。
leetNightshade

149
  • abortはプログラムの「異常な」終了を示し、POSIXシグナルSIGABRTを発生させます。つまり、そのシグナルに登録したハンドラーが呼び出されますが、プログラムはどちらの場合もアフターワードを終了します。通常abortは、Cプログラムで使用して、エラーがプログラムのバグである可能性が高い、予期しないエラーのケースを終了します。誤った入力やネットワーク障害などではありません。たとえば、abort論理的に決して発生してはならないときに、データ構造にNULLポインタが含まれていることが判明した場合などです。

  • exitはプログラムの「正常な」終了を示しますが、これはまだ障害を示している可能性があります(ただし、バグではありません)。つまり、exitユーザーが解析できない入力をしたり、ファイルを読み取れなかったりすると、エラーコードが表示される可能性があります。終了コード0は成功を示します。exitまた、オプションで、プログラムを終了する前にハンドラーを呼び出します。これらはatexitおよびon_exit関数に登録されています。

  • std :: terminateは、未処理の例外があるときにC ++プログラムで自動的に呼び出されるものです。これはabort、例外をスローすることによってすべての例外エラーを報告していると仮定すると、基本的にと同等のC ++ です。これは、std::set_terminate関数によって設定されたハンドラーを呼び出します。このハンドラーは、デフォルトでは単にを呼び出しますabort

C ++では、通常、呼び出しabortexitエラーの発生を回避する必要があります。例外をスローし、コードを呼び出しスタックのさらに上の方に置いて、プログラムの終了が適切かどうかを判断する方がよいからです。exit成功のために使用するかどうかは状況の問題です-のreturnステートメント以外の場所でプログラムを終了することが理にかなっているかどうかmain

std::terminateC ++であっても、最後の溝のエラー報告ツールと見なす必要があります。の問題std::terminateは、終了ハンドラーが処理されなかった例外にアクセスできないため、それが何であったかを知る方法がないことです。通常は、main全体を1つのtry { } catch (std::exception& ex) { }ブロックでラップする方がはるかに優れています。少なくとも、そこから派生した例外に関する詳細情報を報告できますstd::exception(もちろん、派生しない例外はstd::exception処理されないままになります)。

mainin の本体をラップするtry { } catch(...) { }ことは、問題の例外にアクセスできないため、終了ハンドラーを設定するよりもはるかに優れています。編集:ニール・バターワースの回答によると、この場合スタックが巻き戻されるという利点があります。これは(多少意外にも)未処理の例外には当てはまりません。


10
この回答をC ++ 11情報で更新できますか?catch(...)とterminateハンドラーで例外を取得する方法があるようです。
Klaim

1
C ++では、終了ハンドラを介して例外にアクセスできますstd::current_exception()。ここの例を参照してください:akrzemi1.wordpress.com/2011/10/05/using-stdterminate
anorm

検査できないため、現在の例外を取得できるかどうかは関係ありません。あなたができることはそれを再投げるだけです。
seattlecpp 2017

2
@seattlecpp再スローして参照をキャッチし、検査することができます
gpeche

16

std :: abortとstd :: exit(さらに:std :: _ Exit、std :: quick_exit)は、より低いレベルの関数です。それらを使用して、どのデストラクタ(およびif)を呼び出すか、他にどのクリーンアップ関数を呼び出すか、どの値を返すかなど、プログラムに正確に何を実行させたいかを伝えます。

std :: terminateは、より高いレベルの抽象化です。プログラムでエラーが発生し、何らかの理由で例外をスローして処理できないことを示すために(ランタイムまたはユーザーによって)呼び出されます。通常、その必要性は、例外メカニズム自体でエラーが発生した場合に発生しますが、特定のエラーを超えてプログラムを継続させたくない場合はいつでも使用できます。私の投稿で std :: terminateが呼び出された状況の完全なリストをまとめました。std :: terminateが何を行うかは、ユーザーが制御しているため、指定されていません。関数を登録することで動作を設定できます。あなたが持っている制限は、関数がエラーサイトに戻ることができず、例外を介して終了できないことですが、技術的には内部でメッセージポンプを開始することもできます。内部で実行できる便利なことのリストについては、他の投稿を参照しください。

特に、処理できなかった例外がスローされたためにstd :: terminateが呼び出されたコンテキストでは、std :: terminateが例外ハンドラーと見なされ、C ++を使用して例外を確認して検査できることに注意してください。 11 std :: rethrow_exceptionとstd :: current_exceptionを使用します。それはすべて私の投稿にあります。


システムシグナルが原因でプログラムが終了した場合に備えて、クリーンアップハンドラーを用意することをお勧めしますか?たとえば、無効なメモリアクセスにより、SIGSEGV信号が生成されます。この場合、プログラムを終了させて​​コアファイルを用意するか、クリーンアップを実行するためのシグナルハンドラーを登録するだけですか?std :: terminateの処理中にクリーンアップを実行する場合と比較して、システム信号の処理中にクリーンアップを実行することに懸念はありますか?
kartik trivikram

12

quick_exit()

プログラムがマルチスレッドの場合、exit()グローバル/静的std::threadオブジェクトはスレッドを終了せずに破棄しようとするため、呼び出しがクラッシュする可能性が最も高くなります。

エラーコードを返してプログラムを(多かれ少なかれ)正常に終了する場合はquick_exit()、マルチスレッドプログラムで呼び出します。異常終了の場合(エラーコードを指定する可能性はありません)、abort()またはstd::terminate()呼び出すことができます。

注:quick_exit()は、バージョン2015までMSVC ++でサポートされていませんでした


4
  • terminateは、呼び出されたときに何が起こるかを登録する可能性を残します。他の2つのうちの1つである必要があります。
  • exitは、終了ステータスを指定できる通常の終了です。at_exit()によって登録されたハンドラーが実行されます
  • 異常終了は異常終了です。実行されるのは、SIGABRTのシグナルハンドラだけです。

4
  • terminate()は、処理できない例外が発生すると自動的に呼び出されます。デフォルトでは、terminate()はabort()を呼び出します。set_terminate()関数を使用してカスタムハンドルを設定できます。

    abort()はSIGABRTシグナルを送信します。

    exit()は必ずしも悪いことではありません。アプリケーションを正常に終了し、atexit()関数をLIFO順に呼び出します。通常、C ++アプリケーションではこれは見られませんが、最後に終了コードを送信する多くのUNIXベースのアプリケーションでは見られます。通常、exit(0)はアプリケーションの実行が成功したことを示します。


8
失敗!UnixとDOSの両方で、exit(0)は成功を示し、exit()に渡されたその他の値は失敗を示します。
Richard Barrell、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.