第46章 えっ!? 2

 今回は、前回のプログラムをもっと洗練させます。かなりすっきりしますよ。


 それでは、今回の要点です。


 では、いってみましょう。


 goto を使うよりも綺麗になるといっておきながら、前回のプログラムは大して変わっていませんでした。今回は、そのあたりを考えてみたいと思います。

 では、もういちど前回のプログラムを見てみましょう。

int Func()
{
    FILE *pf1 = NULL;
    FILE *pf2 = NULL;
    FILE *pf3 = NULL;
    int fRet = 0;

    try
    {
        pf1 = fopen(szFile1, "r");
        if(pf1 == NULL)
            throw 1;

        pf2 = fopen(szFile2, "r");
        if(pf2 == NULL)
            throw 2;

        pf3 = fopen(szFile3, "w");
        if(pf3 == NULL)
            throw 3;

        Func2(pf1, pf2, pf3);
    }
    catch(int fError)
    {
        fRet = fError;
    }

    if(pf1 != NULL)
        fclose(pf1);
    if(pf2 != NULL)
        fclose(pf2);
    if(pf3 != NULL)
        fclose(pf3);

    return fRet;
}

 何が鬱陶しいかといえば、if 文です。goto の時もそうですが、これは一応マクロで簡単にすることができます。

 しかし、例外はそんなものを使わなくてもいいのです。次のプログラムを見て下さい。

FILE* Open(const char* pszFile, const char* pszMode, int fError)
{
    FILE *pf = fopen(pszFile, pszMode);
    if(pf == NULL)
        throw fError;
    return pf;
}

int Func()
{
    FILE *pf1 = NULL;
    FILE *pf2 = NULL;
    FILE *pf3 = NULL;
    int fRet = 0;

    try
    {
        pf1 = Open(szFile1, "r", 1);
        pf2 = Open(szFile2, "r", 2);
        pf3 = Open(szFile3, "w", 3);

        Func2(pf1, pf2, pf3);
    }
    catch(int fError)
    {
        fRet = fError;
    }

    if(pf1 != NULL)
        fclose(pf1);
    if(pf2 != NULL)
        fclose(pf2);
    if(pf3 != NULL)
        fclose(pf3);

    return fRet;
}

 何か Open という関数を作っていますね。で、例外はこの Open の中で投げています。一方、try ブロック内には throw は見あたりません。しかし、try ブロック内から Open を呼んでいます。

 もう分かりましたね。try ブロック内の関数の中で例外が投げられても catch できるのです。Open 内で投げられた例外が、関数外にまで届いているとも言えますね。

 このように、例外は関数外にまで届きます。これが例外処理の強力たる所以です。これでだいぶすっきりしました。


 では、try ブロックがないのに例外が投げられたらどうなるのでしょうか? 早速やってみましょう。

プログラム
// Except1.cpp
int main()
{
    throw 1;
    return 0;
}
実行結果例
abnormal program termination

 問答無用なプログラムですね(笑)。

 結果はいろいろありますが、とにかくエラー終了します。環境によってはそこからデバッグを開始できたりします。


 最後に。ファイルを開くのに関数を作り、ファイルを読み込むのに関数を作り、というのは一見面倒に見えます。ですが、実は CFile クラスを作るときにそれは済ませていますね。CFile クラスの関数を、エラー時に例外を投げるように改造してしまえばいいのです。

// ファイルを開く
void CFile::Open(const char* pszFile, const char* pszFlags)
{
    Close();

    char bufFlags[8];
    if(ModifyFlags(pszFlags, bufFlags, numof(bufFlags)) == false)
        return false;

    m_pfile = fopen(pszFile, bufFlags);
    if(m_pfile == NULL)
        throw 1;
}

bool Func()
{
    CFile file1, file2, file3;

    try
    {
        file1.Open(szFile1, "r");
        file2.Open(szFile2, "r");
        file3.Open(szFile3, "w");

        Func2(file1, file2, file3);
    }
    catch(int fError)
    {
        return false;
    }

    return true;
}

 これでずいぶんとすっきりしましたね。ファイルのクローズがデストラクタで行われるので、そこら辺せこい気もしますが。


 それでは、今回の要点です。


 例外処理の機能はまだまだあります。ぼちぼちとやっていきましょう。

 それでは。


第45章 えっ!? | 第47章 えっ!? 3

Last update was done on 2001.2.27

この講座の著作権はロベールが保有しています