52

C++ の try/catch/finally ブロックについて少し疑問に思っています。__try のようにアンダースコアが 2 つあるこれらのコマンドを見たことがあります。ただし、MVSC 2010 プロジェクトもアンダースコアなしで実行されます。では、いつこれらのアンダースコアが必要になるのでしょうか?

4

3 に答える 3

100

Windows では、例外はオペレーティング システム レベルでサポートされています。構造化例外処理 (SEH) と呼ばれ、Unix シグナルとほぼ同等です。通常、Windows 用のコードを生成するコンパイラはこれを利用して、SEH インフラストラクチャを使用して C++ 例外を実装します。

C++ 標準に従って、throwキーワードとcatchキーワードは C++ 例外をスローしてキャッチするだけです。MSVC コンパイラの対応する SEH 例外コードは 0xe06d7363 です。最後の 3 バイトは「msc」の ASCII コードです。

オペレーティング システムのサポートと統合することは、SEH 例外のスタックの巻き戻し中に C++ デストラクタが呼び出されることも意味します。アンワインドを行うコードは Windows 内にあり、スローによって発生した SEH を SEHとまったく同じ方法で処理します。ただし、Microsoft コンパイラには、デストラクタがすべての場合に呼び出されるようにする必要なコードの生成を回避しようとする最適化があります。オブジェクトの有効期間を制御するスコープ ブロック内に throw ステートメントがないことを証明できる場合は、登録コードをスキップします。これは非同期 SEH 例外と互換性がありません。SEH 例外をキャッチする場合は、/EHa コンパイル オプションを使用してこの最適化を抑制する必要があります。

多くの SEH 例外タイプがあります。オペレーティング システムによって生成されるものは、ntstatus.h SDK ヘッダー ファイルにリストされています。さらに、SEH を使用して独自の例外処理を実装するコードと相互運用する場合は、独自の例外コードを使用します。.NET と同様に、マネージド例外は 0xe0434f4d ("com") 例外コードを使用します。

C++ プログラムで SEH 例外をキャッチするには、非標準の __try キーワードを使用する必要があります。__except キーワードは、C++ のcatchキーワードに似ています。より多くの機能があり、アクティブな例外をキャッチするかどうかを決定する例外フィルター式を指定します。何でも可能ですが、通常は渡された例外情報だけを見て、それを処理することに関心があるかどうかを確認します。__finally キーワードを使用すると、例外が処理された後に実行されるコードを記述できます。C++ ではこれに相当するものはありませんが、他の言語では珍しくありません。

コメントで指摘されているように、これはすべてかなり不十分に文書化されています。その証拠はプリンにあります。これは、あなたが遊ぶことができるサンプルプログラムです。/EHa を使用してコンパイルし、C++ 例外が SEH の上に実装されている場合に、SEH 例外で C++ デストラクタを呼び出す方法を示します。MSVC コンパイラが必要です。デバッガが役に立たないように、Ctrl+F5 で実行します。

#include "stdafx.h"
#include <windows.h>
#include <iostream>

// NOTE: the value of the C/C++, Code Generation, Enable C++ Exceptions setting in important
// Try it both with /EHsc (the default) and /EHa to see the difference

class Example {  
public:
    ~Example() { std::cout << "destructed" << std::endl; }
};

int filterException(int code, PEXCEPTION_POINTERS ex) {
    std::cout << "Filtering " << std::hex << code << std::endl;
    return EXCEPTION_EXECUTE_HANDLER;
}

void testProcessorFault() {
    Example e;
    int* p = 0;
    *p = 42;
}

void testCppException() {
    Example e;
    throw 42;
}

int main()
{
    __try {
        testProcessorFault();
    }
    __except(filterException(GetExceptionCode(), GetExceptionInformation())) {
        std::cout << "caught" << std::endl;
    }
    __try {
        testCppException();
    }
    __except(filterException(GetExceptionCode(), GetExceptionInformation())) {
        std::cout << "caught" << std::endl;
    }
    return 0;
}

出力:

Filtering c0000005
destructed
caught
Filtering e06d7363
destructed
caught
于 2011-08-13T10:14:25.043 に答える
25

__try/__exceptは、一般的な例外をキャッチするためではなく、 SEH(ウィンドウで生成されたエラー)をキャッチするためのものです。

try/catchは、一般的なC++例外を処理するためにC++標準で指定されているものです。

try作成する標準のC++コードでは、常に/catchではなく__try/を使用する必要があります。__except

また、finallyC ++標準で指定された構造ではありません。これは、Microsoftコンパイラ拡張機能であるため、機能します。

于 2011-08-13T09:08:42.583 に答える
4

__try/__except Microsoft固有ですコードを他のコンパイラ(たとえばc g ++)(または)で別のOSでコンパイルできるようにする場合は、それらの使用を避け、標準try/catchのステートメントを使用してください

于 2011-08-13T09:08:21.517 に答える