例外処理の基本原則
1. 例外はプログラム制御メカニズムであり、関数機構とは独立かつ補完的な関係
関数はスタック構造に基づく制御システムであり、例外は別の制御構造です。スタックに依存しつつ、複数の例外タイプを捕捉条件として設定可能で、型マッチングによりスタックフレーム間をジャンプします。
例外処理の目的
従来のスタック機構は規則的な制御を実現しますが、オブジェクト指向プログラミングでは方向性のある制御伝達が要求されます。例外はエラー処理だけでなく、プログラム制御構造を変更しオブジェクト指向プログラミングを支援するために設計されました。
例外処理の実装方法
基本構文
- 例外発生時はthrowで例外オブジェクトを作成・送出
- 例外が発生する可能性のあるコードをtryブロックで囲む
- tryブロック内で例外が発生しなければ、後続のcatch句は実行されない
- catch句は出現順に評価され、マッチしたハンドラが例外を処理
- マッチするハンドラがない場合はterminate関数が呼び出される
- 処理できない例外はcatchブロック内で再送出可能
例外ハンドリング実践
int calcMod(int a, int b) {
if (b == 0) throw a;
return a % b;
}
int main() {
try {
std::cout << "8 mod 2 = " << calcMod(8, 2) << '\n';
std::cout << "10 mod 0 = " << calcMod(10, 0) << '\n';
} catch (int value) {
std::cerr << value << " で除算エラーが発生\n";
} catch (...) {
std::cerr << "不明な例外\n";
}
return 0;
}
カスタム終了処理
#include <exception>
void customTerminate() {
std::cout << "カスタム終了処理が呼び出されました\n";
std::abort();
}
int main() {
std::set_terminate(customTerminate);
// ...
}
コンストラクタと例外
class Resource {
public:
Resource() {
if (/* 初期化失敗 */) throw std::runtime_error("初期化エラー");
}
};
void initialize() {
try {
Resource res;
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
}
}
型マッチングの特性
struct TypeA {};
struct TypeB {};
void process() {
try {
throw TypeA();
} catch (const TypeB&) {
// TypeA例外は捕捉されない
} catch (const TypeA&) {
// 正しく捕捉される
}
}