exit()とabort()の違いは何ですか?


回答:


116

abort()atexit()最初に使用して登録された関数を呼び出すことなく、またオブジェクトのデストラクタを最初に呼び出すことなく、プログラムを終了します。exit()プログラムを終了する前に両方を行います。ただし、自動オブジェクトのデストラクタは呼び出されません。そう

A a;
void test() { 
    static A b;
    A c;
    exit(0);
}

ab適切に破棄しますが、のデストラクタを呼び出しませんcabort()どちらのオブジェクトのデストラクタも呼び出しません。これは残念なことに、C ++標準は適切に終了することを保証する別のメカニズムを記述しています:

自動ストレージ期間を持つオブジェクトは、関数main()に自動オブジェクトが含まれておらず、への呼び出しを実行するプログラムですべて破棄されますexit()main()でキャッチされる例外をスローすることで、コントロールを直接に転送できますmain()

struct exit_exception { 
   int c; 
   exit_exception(int c):c(c) { } 
};

int main() {
    try {
        // put all code in here
    } catch(exit_exception& e) {
        exit(e.c);
    }
}

を呼び出す代わりにexit()、そのコードthrow exit_exception(exit_code);を配置します。


2
+1。BrianR. Bondyは良かったが、中止/終了の問題(スタックオブジェクトのデストラクタではなく)が発生し、RAIIを多用するC ++プロセスの代替案が提供されたため。
paercebal 2009年

私はdtorを呼び出さずにプログラムを終了する方法を探していましたが、あなたの答えは私が探していたものです!ありがとう
acemtp 2009

もちろん、自動オブジェクトデストラクタが呼び出されないことが実際に重要である場合、それは完全に正しいです:-)
Chris Huang-Leaver

私の知る限り、exitとabortのもう1つの違いは、(オペレーティングシステムの構成によっては)コアダンプが生成される可能性があることです。
Dirk Herrmann

33

abortはSIGABRTシグナルを送信し、exitは通常のクリーンアップを実行しているアプリケーションを閉じるだけです。

アボートシグナルは必要に応じて処理できますが、デフォルトの動作では、エラーコードを使用してアプリケーションも終了します。

abortは静的メンバーとグローバルメンバーのオブジェクト破棄を実行しませんが、終了します。

もちろん、アプリケーションが完全に閉じられると、オペレーティングシステムは解放されていないメモリやその他のリソースを解放します。

(デフォルトの動作をオーバーライドしなかったと仮定して)アボートプログラムと終了プログラムの両方の終了で、戻りコードは、アプリケーションを開始した親プロセスに返されます。

次の例を参照してください。

SomeClassType someobject;

void myProgramIsTerminating1(void)
{
  cout<<"exit function 1"<<endl;
}

void myProgramIsTerminating2(void)
{
  cout<<"exit function 2"<<endl;
}

int main(int argc, char**argv)
{
  atexit (myProgramIsTerminating1);
  atexit (myProgramIsTerminating2);
  //abort();
  return 0;
}

コメント:

  • 中止がコメント化されていない場合:何も出力されず、someobjectのデストラクタは呼び出されません。

  • もし アボートは、上記のようにコメントしている:SomeObjectのデストラクタを使用すると、次のような出力が得られます呼び出されます。

出口機能2
出口機能1


ここでは、exit function 2 THEN exit function 1と呼ばれています。gcc4、Linux 2.6。
ストレッジャー2008

1
atexitのmanページには、「関数[atexitを使用して登録された]は逆の順序で呼び出され、引数は渡されません。」と書かれています。
ストレッジャー2008

@stragerは正しいです。exitが呼び出されるかメインリターンが返されると、atexitによって登録された関数が逆の順序で呼び出されることになっています。
ロバートギャンブル、

テストを実行したところ、グローバルインスタンスへのデストラクタがすべてのatexitコールバックの後に呼び出されたようです。
ストレッジャー2008

+1は、abort()呼び出しの後でさえ、OSが最終的にすべての割り当てられたリソースを解放することを人々に思い出させるために。
Fingolfin 2012年

10

プログラムがexit()を呼び出すと、次のことが起こります。

  • 関数によって登録されたatexit関数が実行されます
  • 開いているすべてのストリームがフラッシュされて閉じられ、によって作成されたファイルtmpfileが削除されます
  • プログラムは、指定された終了コードでホストに終了します。

abort()関数は送信しSIGABRT、それがプログラムは、オープンストリームが/フラッシュ閉じていることかによって作成される一時ファイルという保証なしで終了したキャッチされていない場合は、現在のプロセスにシグナルをtmpfile除去したが、atexit登録された関数が呼び出されていない、と非ゼロの終了ステータスがホストに返されます。


うーん。標準では、シグナルハンドラが「返らない」場合にのみプログラムが終了しないと規定しています。あなたはCにかなり満足しています。戻ることなく通常の実行を継続できるようにするシナリオを想像できますか?私はlongjmpを想像しますが、それがシグナルハンドラでどのように動作するかはわかりません。
Johannes Schaub-litb 2008

一般に、シグナルハンドラーからのlongjmpの呼び出しは定義されていませんが、レイズ/アボートでシグナルが生成された場合の特別なケースがあるため、理論的には可能だと思いますが、これまでに実行したことはないと思います。今、私はそれを試さなければならないつもりです;)
ロバートギャンブル

1
これは機能しているようです(300文字の制限により複数の投稿に分割されています)。jmp_buf env; void abort_handler(int i){do_abort = 0; longjmp(env、1);}
ロバートギャンブル

int main(void){setjmp(env); puts( "At setjmp"); if(do_abort){signal(SIGABRT、abort_handler); puts( "Calling abort"); アボート(); puts( "中止しませんでした!"); 0を返します。}
ロバートギャンブル、

Ubuntu 7.04の場合、次のように出力されます。
ロバートギャンブル、

5

exit()マニュアルページから:

exit()関数は通常のプロセスを終了させ、ステータス&0377の値が親に返されます。

abort()マニュアルページから:

abort()は最初にSIGABRTシグナルのブロックを解除し、次に呼び出しプロセスに対してそのシグナルを発生させます。これにより、SIGABRTシグナルがキャッチされ、シグナルハンドラーが返らない限り、プロセスが異常終了します。


4

abortSIGABRTシグナルを送信します。 abort呼び出し元に戻りません。SIGABRTシグナルのデフォルトのハンドラーは、アプリケーションを閉じます。 stdioファイルストリームはフラッシュされてから閉じられます。ただし、C ++クラスインスタンスのデストラクタはありません(これについては不明です-おそらく結果は未定義ですか?)。

exitで設定される独自のコールバックがありますatexit。コールバックが指定されている(または1つだけ)場合、それらは(スタックのように)登録順とは逆の順序で呼び出され、プログラムは終了します。同様にabortexit呼び出し元に戻りません。 stdioファイルストリームはフラッシュされてから閉じられます。また、C ++クラスインスタンスのデストラクタが呼び出されます。


exitは、atexitを介して登録された複数のコールバック関数を持つことができます。exitが呼び出されると、すべてのコールバック関数が、登録されたときとは逆の順序で呼び出されます。
ロバートギャンブル、

@Gamble、もちろん、私は数分前に@Bondyの回答へのコメントで自分自身について述べました。それを反映するために自分の答えを編集します。
ストレッジャー2008
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.