目次
はじめに
C++のプログラムは、通常はmain関数の最後まで実行され、return 0; によって正常に終了します。しかし、時にはプログラムの途中で、特定の条件に基づいて即座に終了させたい場合があります。
C++の標準ライブラリ <cstdlib> と <exception> は、このようなプログラムの終了を制御するための関数を提供しています。この記事では、4つの主要なプログラム終了方法と、それぞれのデストラクタの呼び出しに関する重要な違いを解説します。
終了方法を確認するサンプルコード
このコードは、グローバルオブジェクトとローカルオブジェクトのデストラクタが、どの終了方法で呼び出されるかを示します。
完成コード
#include <iostream>
#include <cstdlib> // exit, quick_exit
#include <exception> // terminate
using namespace std;
// デストラクタでメッセージを表示するクラス
struct Monitor {
string name;
Monitor(string n) : name(n) {}
~Monitor() { cout << "デストラクタ: " << name << endl; }
};
// グローバルオブジェクト
Monitor global_monitor("グローバル");
// at_quick_exit で登録する関数
void on_quick_exit() {
cout << "at_quick_exit ハンドラが呼ばれました。" << endl;
}
int main() {
// at_quick_exitに関数を登録 (C++11)
at_quick_exit(on_quick_exit);
Monitor local_monitor("ローカル(main)");
cout << "どの方法で終了しますか?" << endl;
cout << "1: 正常終了 (return)" << endl;
cout << "2: std::exit" << endl;
cout << "3: std::quick_exit" << endl;
cout << "4: std::terminate" << endl;
int choice;
cin >> choice;
switch(choice) {
case 1:
cout << "--- 正常終了します ---" << endl;
return 0; // 正常終了
case 2:
cout << "--- std::exitで終了します ---" << endl;
exit(0);
case 3:
cout << "--- std::quick_exitで終了します ---" << endl;
quick_exit(0);
case 4:
cout << "--- std::terminateで異常終了します ---" << endl;
terminate();
}
return 0;
}
各終了方法の解説
1. 正常終了 (mainからのreturn)
- 動作: 最も標準的で安全な終了方法です。
- デストラクタ: ローカルオブジェクト (
local_monitor) とグローバルオブジェクト (global_monitor) の両方のデストラクタが、スコープのルールに従って正しく呼び出されます。
実行結果 (1を入力):
--- 正常終了します ---
デストラクタ: ローカル(main)
デストラクタ: グローバル
2. std::exit(exit_code)
- 動作: プログラムを即座に終了させます。
- デストラクタ: グローバルオブジェクト (
global_monitor) のデストラクタは呼び出されますが、main関数内のローカルオブジェクト (local_monitor) のデストラクタは呼び出されません。
実行結果 (2を入力):
--- std::exitで終了します ---
デストラクタ: グローバル
3. std::quick_exit(exit_code) (C++11)
- 動作:
exitよりもさらに簡素なクリーンアップで、プログラムを即座に終了させます。 - デストラクタ: いかなるオブジェクトのデストラクタも呼び出されません。
at_quick_exit:at_quick_exitで登録された関数だけが、終了時に呼び出されます。
実行結果 (3を入力):
--- std::quick_exitで終了します ---
at_quick_exit ハンドラが呼ばれました。
4. std::terminate()
- 動作: 回復不能なエラーが発生したことを示し、プログラムを異常終了させます。通常、
throwされた例外がどこでもcatchされなかった場合などに、自動的に呼び出されます。 - デストラクタ: いかなるデストラクタも呼び出されません。
- 意図: 開発者に「何か致命的な問題が起きている」と知らせるためのものであり、通常の終了処理には使いません。
まとめ
| 終了方法 | ローカルデストラクタ | グローバルデストラクタ | at_quick_exit | 用途 |
return from main | 呼ばれる | 呼ばれる | 呼ばれない | 正常終了 |
std::exit | 呼ばれない | 呼ばれる | 呼ばれない | 正常終了(非推奨) |
std::quick_exit | 呼ばれない | 呼ばれない | 呼ばれる | 高速終了 |
std::terminate | 呼ばれない | 呼ばれない | 呼ばれない | 異常終了 |
結論として、プログラムの安全な後片付けを保証するために、可能な限り main 関数からの return でプログラムを終了させるべきです。 exit 系の関数は、RAIIの原則を破壊するため、その挙動を完全に理解した上で、限定的に使用する必要があります。
