次の方法で共有


構造化例外処理 (C/C++)

Windows および Visual C++ は構造化例外処理 (SEH) をサポートしていますが、コードの移植性と柔軟性が高くなる ISO 標準の C++ 例外処理を使用することをお勧めします。 ただし、既存のコードや特定の種類のプログラムでは、SEH を使用する必要がある場合もあります。

文法

try-except-statement :

__try compound-statement

__except ( expression ) compound-statement

解説

SEH を使うと、実行が予期せずに終了した場合にメモリ ブロックやファイルなどのリソースが適切であることを確認できます。 また、メモリ不足などの特定の問題を、goto ステートメントやリターン コードの複雑なテストに依存しない簡潔な構造化されたコードを使用して処理することもできます。

ここで説明する try-except および try-finally ステートメントは C 言語に対する Microsoft の拡張機能です。 これらは、イベント後にプログラムの制御をアプリケーションが取得するようにし、そうでない場合は実行を終了させることによって SEH をサポートします。 SEH は C++ ソース ファイルと連携しますが、C++ 向けに設計されていません。 特定の修飾子と共に /EH オプションを使用してコンパイルした C ++ プログラムで SEH を使用する場合、ローカル オブジェクトのデストラクターは呼び出されますが、他の実行時の動作は予期したとおりにならない可能性があります (概要については、この記事で後述する例を参照してください)。 ほとんどの場合、SEH の代わりに、Visual C++ もサポートする ISO 標準の C++ 例外処理を使用することをお勧めします。 C++ 例外処理を使用すると、コードの移植性が高くなり、すべての種類の例外を処理できるようになります。

SEH を使用する C モジュールがある場合、C++ 例外処理を使用する C++ モジュールとそれらを混在させることができます。 詳細については、「例外処理の相違点」を参照してください。

SEH メカニズムには次の 2 つがあります。

これら 2 種類のハンドラーは区別されますが、"スタックのアンワインド" というプロセスを通じて密接に関係しています。 例外が発生すると、Windows は現在アクティブである最も新しくインストールされた例外ハンドラーを検索します。 ハンドラーは、次の 3 つのうちの 1 つを行うことができます。

  • 例外の認識に失敗し、他のハンドラーに制御を渡す。

  • 例外を認識し、拒絶する。

  • 例外を認識し、処理する。

例外を認識する例外ハンドラーは、例外が発生したときに実行中だった関数内にない場合があります。 場合によっては、スタックのかなり上位の関数内にあります。 現在実行中の関数と、スタック フレーム上の他のすべての関数が終了します。 このプロセスでは、スタックが "アンワインド" されます。つまり、終了した関数のローカル変数は、static でない限りスタックから消去されます。

これがスタックをアンワインドするため、オペレーティング システムは、各関数に書き込んだ終了ハンドラーを呼び出します。 終了ハンドラーを使用して、異常終了のために開いたままになっているリソースをクリーンアップできます。 クリティカル セクションに入った場合、終了ハンドラーで終了できます。 プログラムがシャットダウンする場合、一時ファイルを閉じたり削除するなどの他のハウスキーピング タスクを実行できます。

詳細については、次のトピックを参照してください。

使用例

前に説明したように、C++ プログラムで SEH を使用し、特定の修飾子 (たとえば /EHsc/EHa) と共に /EH オプションを使用してコンパイルすると、ローカル オブジェクトのデストラクターが呼び出されます。 ただし、C++ 例外も使用している場合は、実行時の動作は予期したとおりにならない可能性があります。 次の例は、これらの動作の違いを示しています。

#include <stdio.h>
#include <Windows.h>
#include <exception>
 
class TestClass
{
public:
    ~TestClass()
    {
        printf("Destroying TestClass!\r\n");
    }
};
 
__declspec(noinline) void TestCPPEX()
{
#ifdef CPPEX
    printf("Throwing C++ exception\r\n");
    throw std::exception("");
#else
    printf("Triggering SEH exception\r\n");
    volatile int *pInt = 0x00000000;
    *pInt = 20;
#endif
}
 
__declspec(noinline) void TestExceptions()
{
    TestClass d;
    TestCPPEX();
}
 
int main()
{
    __try
    {
        TestExceptions();
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        printf("Executing SEH __except block\r\n");
    }
 
    return 0;
}

/EHsc を使用してこのコードをコンパイルするがローカル テスト コントロール CPPEX が定義されていない場合、TestClass デストラクターの実行はされず、出力は次のようになります。

  

/EHsc を使用してコードをコンパイルし、/DCPPEX を使用して CPPEX が定義されている場合 (C++ 例外がスローされる)、TestClass デストラクターが実行され、出力は次のようになります。

  

/EHa を使用してコードをコンパイルする場合、std::throw を使用して例外がスローされたか、または SEH を使用して例外をトリガーしたか (CPPEX が定義されたかどうか) に関係なく、TestClass デストラクターが実行されます。 出力は次のようになります。

  

詳細については、「/EH (例外処理モデル)」を参照してください。

参照

関連項目

Visual C++ での例外処理

C++ キーワード

<exception>

概念

エラーと例外の処理 (Modern C++)

その他の技術情報

構造化例外処理 (Windows)