C++例外処理のススメ
Java をはじめとするいくつかの言語は、実行時に発生したエラーを処理する仕組みとして、例外処理機構を採用しています。
例外処理を使うと、戻り値でエラーを検知・処理する手法よりも確実に行うことができる上、コードの記述も簡潔になります。
C++ もこの例外処理を採用していますが、Java のそれと比べても明らかに普及していません。
その理由としては、
- 前身である C から、従来のエラー処理手法 (戻り値で検出) が尾を引いている。
- Java の Exception のような、標準の例外型が存在しない。
- 例外の補足・処理が強制されない。(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) |
このように、エラーの詳細をメッセージ (文字列) として関数の呼び出し元に通知することができます。
また、例外の発生位置およびスローされてきた経路 (スタック履歴) を参照することも可能です。
これらの機能は、デバッグの際に大きな助けとなること間違いなし。
皆様もぜひご活用ください。
担当: 成田 (例外スロア)

コメントを投稿