構造化例外処理 (C/C++)
構造化例外処理 (SEH) は、ハードウェア障害などの特定の例外的なコード状況を適切に処理するための、C および C++ に対する Microsoft 拡張機能です。 Windows Microsoft C++ では SEH がサポートされています。ただし、C++ コードで ISO 標準の C++ 例外処理を使用することをお勧めします。 これにより、コードの移植性と柔軟性が向上します。 ただし、既存のコードや特定の種類のプログラムを維持するために、SEH を使用する必要がある場合もあります。
Microsoft 固有の仕様:
構文
try-except-statement
は、次のとおりです。
__try
compound-statement
__except
(
filter-expression
)
compound-statement
try-finally-statement
は、次のとおりです。
__try
compound-statement
__finally
compound-statement
解説
SEH を使うと、実行が予期せずに終了した場合にメモリ ブロックやファイルなどのリソースが適切にリリースされることを確認できます。 また、メモリ不足などの特定の問題を、goto
ステートメントやリターン コードの複雑なテストに依存しない簡潔な構造化されたコードを使用して処理することもできます。
ここで説明する try-except
および try-finally
ステートメントは、C および C++ 言語に対する Microsoft の拡張機能です。 これらは、イベント後にプログラムの制御をアプリケーションが取得するようにし、そうでない場合は実行を終了させることによって SEH をサポートします。 SEH は C++ ソース ファイルと連携しますが、C++ 向けに設計されていません。 /EHa
または /EHsc
オプションを使用してコンパイルした C ++ プログラムで SEH を使用する場合、ローカル オブジェクトのデストラクターは呼び出されますが、他の実行時の動作は予期したとおりにならない可能性があります。 概要については、この記事で後述する例を参照してください。 ほとんどの場合、SEH の代わりに、ISO 標準の C++ 例外処理を使用することをお勧めします。 C++ 例外処理を使用すると、コードの移植性が高くなり、すべての種類の例外を処理できるようになります。
SEH を使用する C コードがある場合は、C++ 例外処理を使用する C++ コードと混在できます。 詳細については、「C++ での構造化例外の処理」を参照してください。
SEH メカニズムには次の 2 つがあります。
filter-expression
値に基づいて例外に対処または例外を拒絶できる例外ハンドラー、つまり__except
ブロックです。 詳細については、「try-except
ステートメント」をご覧ください。例外によって終了が発生するかどうかに関係なく、常に呼び出される終了ハンドラー、または
__finally
ブロック。 詳細については、「try-finally
ステートメント」をご覧ください。
これら 2 種類のハンドラーは区別されますが、"スタックのアンワインド" というプロセスを通じて密接に関係しています。 構造化例外が発生すると、Windows は現在アクティブである最も新しくインストールされた例外ハンドラーを検索します。 ハンドラーは、次の 3 つのうちの 1 つを行うことができます。
例外の認識に失敗し、他のハンドラーに制御を渡す (
EXCEPTION_CONTINUE_SEARCH
)。例外を認識し、拒絶する (
EXCEPTION_CONTINUE_EXECUTION
)。例外を認識し、処理する (
EXCEPTION_EXECUTE_HANDLER
)。
例外を認識する例外ハンドラーは、例外が発生したときに実行中だった関数内にない場合があります。 スタックのかなり上位の関数内にあります。 現在実行中の関数と、スタック フレーム上の他のすべての関数が終了します。 このプロセス中、スタックはアンラウンドされます。 つまり、終了した関数のローカルの非静的変数はスタックからクリアされます。
これがスタックをアンワインドするため、オペレーティング システムは、各関数に書き込んだ終了ハンドラーを呼び出します。 終了ハンドラーを使用して、異常終了のために開いたままになっているリソースをクリーンアップします。 クリティカル セクションに入った場合、終了ハンドラーで終了できます。 プログラムのシャットダウン時に、一時ファイルを閉じたり削除するなどの他のハウスキーピング タスクを実行できます。
次のステップ
例
前に説明したように、C++ プログラムで SEH を使用し、/EHa
または /EHsc
オプションを使用してコンパイルすると、ローカル オブジェクトのデストラクターが呼び出されます。 ただし、C++ 例外も使用している場合は、実行時の動作は予期したとおりにならない可能性があります。 この例は、これらの動作の違いを示しています。
#include <stdio.h>
#include <Windows.h>
#include <exception>
class TestClass
{
public:
~TestClass()
{
printf("Destroying TestClass!\n");
}
};
__declspec(noinline) void TestCPPEX()
{
#ifdef CPPEX
printf("Throwing C++ exception\n");
throw std::exception("");
#else
printf("Triggering SEH exception\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\n");
}
return 0;
}
/EHsc
を使用してこのコードをコンパイルするが、ローカル テスト コントロール マクロ CPPEX
が未定義の場合、TestClass
デストラクターは実行されません。 出力は次のようになります。
Triggering SEH exception
Executing SEH __except block
/EHsc
を使用してコードをコンパイルし、/DCPPEX
を使用して CPPEX
が定義されている場合 (C++ 例外がスローされる)、TestClass
デストラクターが実行され、出力は次のようになります。
Throwing C++ exception
Destroying TestClass!
Executing SEH __except block
/EHa
を使用してコードをコンパイルした場合、TestClass
デストラクターは、標準 C++ throw
式を使用して例外がスローされたか、SEH を使用してスローされたかに関わらず実行されます。 つまり、CPPEX
が定義されているかどうかを示します。 出力は次のようになります。
Throwing C++ exception
Destroying TestClass!
Executing SEH __except block
詳細については、「/EH
(例外処理モデル)」を参照してください。
Microsoft 固有の仕様の終了
関連項目
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示