読者です 読者をやめる 読者になる 読者になる

C++例外処理のススメ

Java をはじめとするいくつかの言語は、実行時に発生したエラーを処理する仕組みとして、例外処理機構を採用しています。
例外処理を使うと、戻り値でエラーを検知・処理する手法よりも確実に行うことができる上、コードの記述も簡潔になります。
C++ もこの例外処理を採用していますが、Java のそれと比べても明らかに普及していません。
その理由としては、

  • 前身である C から、従来のエラー処理手法 (戻り値で検出) が尾を引いている。
  • JavaException のような、標準の例外型が存在しない。
  • 例外の補足・処理が強制されない。(Java では throws キーワードを使用してこれを強制する。)

などが考えられます。
これらのうち、1. 2. を解決すべく、Java に負けじと C++ 版 Exception を作成してみました。

※本エントリ内のファイルの公開を終了しました。

これを使えば、従来よりも簡単かつ便利に例外処理を行うことができます。

Exception を用いたコーディングの例を以下に示します。
(ファイル hoge.txt を piyo.txt にコピーするプログラムです。)

#include "narita/Exception.h"
#define BUF_SIZE 256
typedef const char* LPCSTR;
void    CopyFile(LPCSTR lpszFilenameSrc, LPCSTR lpszFilenameDst);
FILE*   OpenFile(LPCSTR lpszFilename, LPCSTR lpszMode);
//エントリポイント
int main(){
try {
CopyFile("hoge.txt", "piyo.txt");
}
catch (Exception& e){
e.Print(stderr);
}
return 0;
}
//ファイルのコピー
void CopyFile(LPCSTR lpszFilenameSrc, LPCSTR lpszFilenameDst){
FILE* fpSrc =NULL;
FILE* fpDst =NULL;
try {
fpSrc =OpenFile(lpszFilenameSrc, "rb");
fpDst =OpenFile(lpszFilenameDst, "wb");
for (;;){
char acBuf[BUF_SIZE];
int nRead =fread(acBuf, 1, BUF_SIZE, fpSrc);
if (!nRead){
if (::ferror(fpSrc))
throw Exception::create(__FILE__, __LINE__, "Read error occured.");
else
break;
}
int nWrite =fread(acBuf, 1, nRead, fpDst);
if (nWrite < nRead){
throw Exception::create(__FILE__, __LINE__, "Write error occured.");
}
} //for (;;)
fclose(fpSrc);
fclose(fpDst);
return;
}
catch (Exception& e){
if (fpSrc) fclose(fpSrc);
if (fpDst) fclose(fpDst);
throw e.Relay(__FILE__, __LINE__);
}
}
//ファイルを開く
FILE* OpenFile(LPCSTR lpszFilename, LPCSTR lpszMode){
FILE* fp =fopen(lpszFilename, lpszMode);
if (!fp){
throw Exception::createf(__FILE__, __LINE__, "File '%s' cannot be opened.", lpszFilename);
}
return fp;
}

ファイル hoge.txt が開けない場合、実行結果は次のようになります。

File 'hoge.txt' cannot be opened.
/home/narita/test.cpp(70)
/home/narita/test.cpp(61)

このように、エラーの詳細をメッセージ (文字列) として関数の呼び出し元に通知することができます。
また、例外の発生位置およびスローされてきた経路 (スタック履歴) を参照することも可能です。

これらの機能は、デバッグの際に大きな助けとなること間違いなし。
皆様もぜひご活用ください。

担当: 成田 (例外スロア)