例外処理の基本

Last-modified: 2006-12-05 (火) 16:39:20

例外処理を行うべきケース

  • 実行中にユーザの操作によって外部ストレージが外された
  • 実行中に対象のファイルが外部プログラムで更新された
  • 使用しているライブラリで起こる例外

基本

  • できるだけ例外が起こらない仕様にする
  • 例外は値で投げる
  • 例外は参照で受ける
  • 例外にモジュール境界を越えさせない(必ずキャッチ)

例外指定

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;
}