構造化例外処理 (C/C++)
構造化例外処理 (Standard Edition H) は、ハードウェア 障害などの特定の例外的なコード状況を適切に処理するための C および C++ の Microsoft 拡張機能です。 Windows および Microsoft C++ では Standard Edition H がサポートされていますが、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++ 向けに設計されていません。 または/EHsc
オプションを使用してコンパイルする C++ プログラムで Standard Edition H を使用/EHa
する場合、ローカル オブジェクトのデストラクターが呼び出されますが、他の実行動作が予期した動作ではない可能性があります。 概要については、この記事で後述する例を参照してください。 ほとんどの場合、Standard Edition H ではなく、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 を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示