Codelogy

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)

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

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

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

コメントを投稿

コメントの公開は承認制のため、投稿から掲載までに時間がかかることがあります。


About

2007年09月27日 23:00 に投稿されたエントリです。

他にも多くのエントリがあります。
メインページアーカイブページもご覧ください。