Structured Exception Handling(SEH)

  • デル株式会社
  • 2003/10/31

     

      例外処理というとtry ~ catch文を思い浮かべるかと思います。
    try ~ catchはANSI/ISO C++の仕様で決まっていてどのプラットフォーム
    でも利用できます。同然のことながら、メモリー・アクセス違反や0による除算
    等のCPUによる例外はこのtry ~ catchでは対処できない。
    でっ、CPUによる例外が発生するとアプリケーションは強制終了してまう。
    この、強制終了はWindowsによる構造化例外処理のデフォルトの処理なのです。
    ただこの処理Windows任せにしたくない場合がある。。絶対強制終了しないアプリケーション
    なんかを作らなきゃいけない場合。。(パッケージなんかには組み込むべきなのかなぁ)
    そんな時はSEHが役立ちます。
    ちなみに、SEHはWindowsが提供している機能なのでWindowsでなければ使えません。
    でっ、今日はここまで。。寝る・・

    2003/11/03

    続き書く。でも、眠い・・・
    とりあえずサンプル

    //サンプル1
    int CTest::Test()
    {
         int a = 0;
         int b = 1;
         int c = 0;

         __try
         {
             c = b / a;
         }
         __except(Filter())
         {
             MessageBox("例外発生");
         }

    }

    int CTest::Filter()
    {
         return EXCEPTION_EXECUTE_HANDLER;
    }

    当然ですが以下のコードはダメ。。

    int CTest::Test()
    {
         int a = 0;
         int b = 1;
         int c = 0;

         try
         {
             c = b / a;
         }
         catch(CException* exp)
         {
             MessageBox("例外発生");
         }

    }

    まぁ、ビルドレベル4にしたら、「warning C4702: 制御が渡らないコードです。」て警告でますが・・・
    ちなみに、メソッド内にCStringとか使ったコード書けばwarningはでないです。
    なんでかは、調べてね。。

    でっ、例外処理に使うキーワードは以下にのように3つあります。

    __try
    __except(例外フィルタ)
    __finally

    これを組み合わせて使う事になります。__exceptと__finallyを併せて使うことはできないです。
    __try

    __tryブロックは、その中で呼び出した関数やさらに、その中で呼び出した関数内コードも含み
    例外を評価します。__tryブロックが入れ子等になっている場合は、一番内側の__tryブロックで例外
    を処理します。
    __except

    __exceptキーワードは、サンプルのように例外フィルタを実装しなければなりません。
    例外フィルタは関数の呼び出しや複数の式でもをつかう。
    だから、__except(EXCEPTION_EXECUTE_HANDLER)でもOK。
    最終的には、結果が下の表のいずれかになるようにする。

     

    定数名 説明
    EXCEPTION_CONTINUE_EXECUTION -1 例外を起こしたマシン語命令から実行を再開する。
    __exceptブロックは実行しない
    EXCEPTION_CONTINUE_SEARCH 0 例外を処理せず、外側の__tryブロックに対応する
    例外フィルタの評価に移る
    EXCEPTION_CONTINUE_HANDLER 1 __exceptブロック内のコードを実行する

     

    もちょっと補足・・

    EXCEPTION_CONTINUE_EXECUTIONは例外を起こしたマシン語命令から再開するので、
    例外フィルタで例外の元を取り除く事が前提となる。

    EXCEPTION_CONTINUE_SEARCHは__exceptブロックのコードは実行しない。
    その外側の__tryブロックの例外フィルタに処理を 移す。
    仮にその外側に__tryが無い場合は、Windowsが用意しているデフォルトの例外ハンドラが実行される。

    EXCEPTION_CONTINUE_HANDLER説明要らないと思う。

    __finally

    __finallyキーワードは、例外が発生した時の後しまつをするためのもので、
    仮に下記のようなコード①を実行した場合、動的にメモリーを確保している場合、
    確保後に例外が発生したらそれ以降の処理が実行されない可能性があるので、メモリーリーク
    を起こしてしまう。
    __exceptキーワードと違う点は例外が発生する、しないに関わらず__finallyブロックは実行される。
    ②のコードをみると例外が発生する前に、__tryブロック内でreturnで抜けているが
    __finallyは実行されていることがわかる。
     
    ただ、微妙に使いずらいなぁと思う。。

    コード①

    int CTest::Test()
    {
        int a = 0;
        int b = 1;
        int c = 0;

        char* pChar;

        __try
        {
            pChar = new char[100];
            c = b / a;
        }
        __finally
        {
            delete []pChar;
            MessageBox("絶対処理");

        }
    }

    コード②

    int CTest::Test()
    {
         int a = 0;
         int b = 1;
         int c = 0;

         __try
         {
             return 0;
             c = b / a;
         }
         __finally
         {
             MessageBox("例外発生");
         }
    }

    暇が出来たらもちょっと突っ込んだ説明書きたいと思う今日この頃。。
    インラインアセンブラとかを使って説明書いたら、
    もっと詳しく理解できると思うので。。まぁ、気が向いたら・・・

    関連記事

    ページ上部へ戻る