例外処理


例外処理をキャッチする方法
メモリ不足や入出力エラーなどが起きた場合、例外が発生する。 この例外をアプリケーション内でキャッチすることで、 例外発生時にそのアプリケーションが独自の処理をおこなうことができる。

例として、ファイル例外を発生させてみる。

void CUKExceptionDlg::GetFile()
{
	try
	{
		CFile f("d:\\My Documents\\abc.txt", CFile::modeRead);	// …(1)

		……
		AfxMessageBox("OK");
	}
	catch(CFileException* e)
	{
		if( e->m_cause == CFileException::fileNotFound )
			AfxMessageBox("指定されたファイルは存在しません。");
		else
			AfxMessageBox("ファイル例外が発生しました。");

		e->Delete();
	}
}
上記のような関数を作成し、まず(1)の第1引数に実在するファイル名を指定して実行すると、 "OK"と書かれたメッセージボックスが表示されるはずである。 これは正常に処理がおこなわれたため、tryステートメント内で例外が発生せずにステートメントの最後まで達したことを示す。

次に(1)の第1引数を実在しないファイル名に変更して実行すると、 "指定されたファイルは存在しません"と書かれたメッセージボックスが表示される。 これは(1)で存在しないファイルを指定したために例外が発生し、catchステートメントへ処理が移行したことを示している。 catchステートメントの()内に指定された"e"は、生成されたファイル例外オブジェクト(CFileException)へのポインタであり、 このファイル例外オブジェクトのm_causeメンバを見ることで、 どのような原因で例外が発生したか、より詳細に調べることができる。
CFileExceptionはCExceptionの派生クラスであり、他にもCResourceExceptionなど例外の種類によって様々なクラスが用意されている。

また、catchステートメントの最後に

	e->Delete();
という一文があるが、例外オブジェクトはこのようにして削除する必要があるので忘れないこと。
ちなみに、(1)の第1引数を"d:\\"として実行すると、"ファイル例外が発生しました。"というメッセージボックスが表示される。

目次へ



例外処理のスロー
例えば上記のGetFile関数を呼び出すときに、次のような例外処理をおこないたいとする。
	try
	{
		GetFile();
	}
	catch(CFileException* e)
	{
		AfxMessageBox("GetFile関数で例外発生!");
		e->Delete();
	}
この場合、GetFile関数を全く変更せずに実行した場合、例外が発生するとGetFile内で例外処理がおこなわれ、 "GetFile関数で例外発生!"というメッセージボックスは表示されない。
これを表示させるにはどうすればよいかというと、GetFile関数を以下のように書き換える。
void CUKExceptionDlg::GetFile()
{
	try
	{
		……
	}
	catch(CFileException* e)
	{
		if( e->m_cause == CFileException::fileNotFound )
			AfxMessageBox("指定されたファイルは存在しません。");
		else
			AfxMessageBox("ファイル例外が発生しました。");

		throw;  // ここを書き換える
	}
}
このようにすることで、高い階層のcatchブロックに対して例外を再スローすることができるようになる。


※なお、try, catch, throwはC++のステートメントである。 これと似たような処理にTRY, CATCH, THROWがあるがこれらはMFCのマクロであり、多少動作が異なるので注意すること。 (例えばCATCHではDelete処理を自動的におこなう、など)

目次へ