例外処理
例外処理(例外オブジェクト)をサポートしないCなどの言語では、従来から関数(サブルーチン)の戻り値によってその関数(処理)の成否を判定する方法がとられてきた。慣例的に、関数の戻り値を32ビット整数値などで宣言して、関数が成功した場合は0を返し、失敗した場合はエラーコードとして何らかの負数を返すことが多い。さらに簡略化して、成否の結果を真偽値1/0で返すだけにすることもある。戻り値がポインタ型である場合は、成功した場合に有効なポインタすなわち非NULLを返し、失敗した場合に無効なポインタすなわちNULLを返すのが通例である。標準ライブラリや各種APIでは、詳細を伝えるエラーコードを別途errnoのようなグローバル変数に格納することもある。各エラーコードによって失敗の原因を定義しておき、呼び出し側で原因を判定する。
このような戻り値による処理の成否判定には下記のような問題点がある。
戻り値は無視できるため、呼び出し先でエラーが発生しても通常通り処理を継続するプログラムを記述できてしまう。
エラーコードはたいてい32ビットの整数値でしかないため、それ以上の詳細な情報(例えば具体的原因および異常発生個所などを示すエラーメッセージ)を付加することができない。 直前のエラー情報をグローバル変数に格納する設計は、マルチスレッド対応の際に別途スレッドローカルストレージ化が必要となる。
戻り値を毎回チェックする判定文を記述するのが煩雑である。
tryブロック中で呼び出した関数Function0()が(1)のthrowを実行すると、Function1()のcatch文へと制御が移る。C++では後発の言語とは異なり、std::exceptionあるいはその派生型以外の型の値でもthrowで投げることができ、(3)(4)(5)の様に型に対応したcatch文で捕捉することができる。なお、(1)では例示のため複数のthrowを書いているが、実際には1個目のthrowを実行した時点でcatch文に移動する。
例外構文には例外が存在しないことを明示するnoexceptが標準化されている。
C++の特徴的な構文として、(6)の省略子を用いたcatchが存在する。あらゆる例外を捕捉可能であり、他のcatchが取りこぼした例外でも捕まえる必要がある場合に用いる。値を指定しないthrowを捕まえられるのも省略子を用いたcatchだけである。
処理中に使用可能な記憶領域が枯渇した場合の回復は比較的単純である。
大量データを読み込もうとした
システム全体の短期的な記憶領域枯渇
システム全体の長期的な記憶領域枯渇
記憶領域が原因として上記が考えられるがGUIプログラムのイベント処理であれば3以外の状況から回復できる。1,2どちらも現在実行中の処理を中断して処理に使った記憶領域を解放すればプロセスを継続できる可能性がある。特に2の状況であればシステムの記憶領域使用状況が回復を待って再度同じ処理を実行することができる。
CUIの場合でかつ複数のファイルを処理しているような場合1の状況から回復することができる。枯渇が発生した大容量ファイルの処理は無理でもその後の小容量ファイルは処理できる可能性がある。
次にSmalltalkによる回復処理の例を示す: