2014年5月31日土曜日

C++ 例外




コンパイル時のエラーなら、実行できないので

修正箇所も明確です。

しかし、コンパイルしたファイルを実行すると

エラーになることもあります。

この実行時エラーが、例外(Exception)です。

例外は、ゼロ除算やメモリの2重解放、配列の範囲外アクセスなどによって

起こります。実務では、どこで起こったのかすぐにわからないこともよくあります。

このような例外に対応することを例外処理といいます。(^^;)

C++には、例外処理のための仕組みが用意されています。

try, catch文
例外が起こりそうな箇所にtry、例外処理を行う箇所にcatch文を記述します。

構文はこのような形式になります。

try {
    // 例外が起こりそうな、ちょっと自信がないプログラム
}
catch (int &e) {
    // 例外処理
  // 例えば、エラーが起きたというメッセージの表示
}

実行時は、まずtry { } の中を処理し、例外が起こらなかった場合は、

catch { } の中は実行せずに処理を継続します。

もし、try { } の中で例外が起こった場合は、catch { } の中を

実行して、処理継続となります。

ここで、catchの部分に着目すると、catch (int &e) となっています。

カッコの中で、例外の型(クラス名)、変数名(オブジェクト)を指定して

どのような例外を捕捉するのかを決めることができるのです。

それはつまり、指定を間違うと例外が発生しても catch 文を実行せず

そのままスルーなんて事にもなる、ということです...(^^;)

ちなみにすべての例外を受け取るには

catch ( ... ) {
    // 何かの例外処理
}

このように、「...」 ピリオドを3つ記述します。


throw文
処理に応じて、意図的に例外を通知させたいこともあると思います。

その場合は、次のようにthrow文を使って例外の内容を通知できます。

try {
    int Number;
   
    cout << "Please Input Number : ";
    cin >> Number;
    if (Number < 0) { throw -1; }
    cout << "Input Number : " << Number << endl;
}
catch (int error) {
    cout << "負の数はエラーです。エラーコード: " << error << endl;
}


では、今回はメモリをひたすら確保し続けるサンプルコードを使い

try, catch してみるという実験を以下に示します。

100MBメモリ確保して、文字 'a' で初期化を繰り返すプログラム
#include <iostream>
#include <new>        // bad_allocのcatchに必要です
#include <string.h>

using namespace std;

int main(void)
{
    try {
        // 100MB確保を繰り返す
        for (int i = 1; ; i++) {
            char *pStr = new char[104857600];
            cout << i * 100 << "MB" << endl;
            memset(pStr, 'a', 104857600);
        }
    }
    catch (bad_alloc &) {
        cout << "'new' threw an exception..." << endl;
        return -1;
    }

    return 0;
}

実行結果
# ./test
100MB
200MB
'new' threw an exception...
#

ただメモリを確保しただけだと、OSには実際は使っていない

ということが分かっているので仮想メモリを駆使して実メモリ以上を

確保しているように見えます。手元の環境では、3000MBまで到達(^^;)

そのため、memsetで初期化することで、使用していることをアピールします。

非力なマシンなので、すぐに力尽きてしまいました...


結局、何が言いたいのかというと、例外処理はバグの早期発見に役立つ、

品質の良いプログラムを作るための一機能であるということです。(^^)


今日の名言
時の与えるあらゆる利益を迅速に利用せよ。
                               ウィリアム・シェイクスピア

過去の過ちから役に立つ教訓を引き出すためと、高価な代償を払って得た利益を
得るためでない限り、決して過去を顧みるな。
                               ジョージ・ワシントン

憎しみは、他のどんなものよりもエネルギーを消耗する。その消耗のひどさは、
重労働よりも病気よりも、ちゃんと理由があって心配する場合よりも、はるかに
はなはだしい。だから憎しみの炎が自分の体の中へ入ってきたら、すぐさま
消すことだ。その代わりに美しい考えを入れてやろう。我々の精力は神から
授かった貴重なものだから、価値のある者だけに費やさねばならぬ。
                               デール・カーネギー