C++ プログラムの終了

C++ では、次の方法でプログラムを終了できます:

  • exit 関数を呼び出します。
  • abort 関数を呼び出します。
  • main から return ステートメントを実行します。

exit 関数

<stdlib.h> で宣言された exit 関数は、C++ プログラムを終了します。 exit の引数として指定された値は、プログラムのリターン コードまたは終了コードとしてオペレーティング システムに返されます。 慣例により、ゼロのリターン コードは、プログラムが正常に完了したことを意味します。 <stdlib.h> で定義された定数 EXIT_FAILUREEXIT_SUCCESS を使用して、プログラムの成功または失敗を示すことができます。

abort 関数

標準インクルード ファイルの <stdlib.h> で宣言された abort 関数も、C++ プログラムを終了します。 違いexitabortは、exitC++ ランタイム終了処理を実行できる点です (グローバル オブジェクトデストラクターが呼び出されます)。 abort はプログラムを直ちに終了します。 abort 関数では、初期化されたグローバルな静的オブジェクトの通常のデストラクション処理は実行されません。 また、atexit 関数を使用して指定されている特殊な処理も実行されません。

Microsoft 固有: Windows の互換性上の理由から、Microsoft の実装では、特定の abort 状況で DLL 終了コードを実行できる場合があります。 詳細については、abortを参照してください。

atexit 関数

プログラムが終了する前に実行されるアクションを指定するには、atexit 関数を使用します。 atexit の呼び出し以前に初期化されたグローバル静的オブジェクトは、終了処理関数の実行前に破棄されません。

mainreturn ステートメント

return ステートメントを使用すると、main から戻り値を指定できます。 最初のステートメントはreturn、他returnmainステートメントと同様に機能します。 自動変数はすべて破棄されます。 次に、 main 戻り exit 値をパラメーターとして呼び出します。 次の例を考えてみましょう。

// return_statement.cpp
#include <stdlib.h>
struct S 
{
    int value;
};
int main()
{
    S s{ 3 };

    exit( 3 );
    // or
    return 3;
}

exit前の例の and return ステートメントも同様の動作をしています。 どちらもプログラムを終了し、値 3 をオペレーティング システムに返します。 違いは、exitステートメントでは自動変数sreturnを破棄しないということです。

ただし、C++ では、void 以外の戻り値の型を持つ関数は、値を返す必要があります。 main 関数は例外であり、return ステートメントなしで終了できます。 その場合は、呼び出しプロセスに実装固有の値を返します。 (既定では、MSVC は 0 を返します)。

スレッドオブジェクトと静的オブジェクトの破棄

直接呼び出す場合 (またはステートメントのmainreturnに呼び出exitされた場合) は、現在のスレッドに関連付けられているスレッド オブジェクトが破棄されます。 次に、静的オブジェクトは初期化の逆の順序で破棄されます (関数の呼び出しが指定されている atexit場合は、その呼び出しの後)。 次の例は、こうした初期化やクリーンアップがどのように機能するのかを示します。

以下の例では、静的オブジェクト sd1sd2 は、main に入る前に作成、初期化されます。 このプログラムが return ステートメントを使用して終了した後、最初に sd2 が破棄され、その後に sd1 が破棄されます。 ShowData クラスのデストラクターは、これらの静的オブジェクトに関連付けられたファイルを閉じます

// using_exit_or_return1.cpp
#include <stdio.h>
class ShowData {
public:
   // Constructor opens a file.
   ShowData( const char *szDev ) {
   errno_t err;
      err = fopen_s(&OutputDev, szDev, "w" );
   }

   // Destructor closes the file.
   ~ShowData() { fclose( OutputDev ); }

   // Disp function shows a string on the output device.
   void Disp( char *szData ) {
      fputs( szData, OutputDev );
   }
private:
   FILE *OutputDev;
};

//  Define a static object of type ShowData. The output device
//   selected is "CON" -- the standard output device.
ShowData sd1 = "CON";

//  Define another static object of type ShowData. The output
//   is directed to a file called "HELLO.DAT"
ShowData sd2 = "hello.dat";

int main() {
   sd1.Disp( "hello to default device\n" );
   sd2.Disp( "hello to file hello.dat\n" );
}

このコードを記述するもう 1 つの方法は、ブロック スコープを ShowData 持つオブジェクトを宣言することです。これにより、スコープ外になったときに暗黙的に破棄されます。

int main() {
   ShowData sd1( "CON" ), sd2( "hello.dat" );

   sd1.Disp( "hello to default device\n" );
   sd2.Disp( "hello to file hello.dat\n" );
}

関連項目

main関数とコマンドライン引数