例外処理を行うべきケース
- 実行中にユーザの操作によって外部ストレージが外された
- 実行中に対象のファイルが外部プログラムで更新された
- 使用しているライブラリで起こる例外
基本
- できるだけ例外が起こらない仕様にする
- 例外は値で投げる
- 例外は参照で受ける
- 例外にモジュール境界を越えさせない(必ずキャッチ)
例外指定
void function(void) throw(int, char*) {
/* 何か */
}
これは、関数functionが例外としてintかchar*を投げる可能性があることを示す。
逆を言えば、intとchar*以外の例外は投げない。
もちろんfunctionよりも低レベルな部分で投げられた例外を投げる可能性はある。
void function(void) throw() {
/* 何か */
}
これは一切の例外を投げないことを示している。
再スロー
catchした例外を再びthrowしたいときに使う。
catch (int & e) {
throw;
}
次のように、再スローするオブジェクトがないのに再スローしようとした場合
後述のterminate()関数が呼ばれる。
void function(void) {
throw;
}
ターミネータ
例外処理などでcatchしていない例外が起こったとき
最終的には、標準関数terminate()が呼ばれる。
自前の関数を呼ばれるようにするには、
typedef void (*terminate_handler)(); terminate_handler set_terminate(terminate_handler f) throw();
を使って、自前の関数を最初に登録しておく。
関数tryブロック
関数全体をtryブロックにする。
#include <iostream> using namespace std;
void function(void) try {
cout << "function called." << endl;
throw 0;
} catch (int & e) {
cout << "function error: " << e << endl;
throw;
}
int main(void)
{
try {
function();
} catch (int & e) {
cout << "catch in main ... error : " << e << endl;
}
return 0; }
初期化子の例外はtryブロック
初期化子で起こった例外は、tryブロックでしかキャッチできませんので。
以下のようにキャッチしましょう。
class A {
public:
A(string & s) : str(s) try {
} catch (...) {
this->str = "";
}
private:
string str;
}
コンパイルエラーが出るかもしれません、以下もお試しを。
class A {
public:
A(string & s) try : str(s) {
} catch (...) {
this->str = "";
}
private:
string str;
}