web-dev-qa-db-ja.com

C ++、__ tryおよびtry / catch / finally

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

42
martin

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

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

オペレーティングシステムのサポートと統合することは、SEH例外のスタックアンワインド中にC++デストラクタが呼び出されることも意味します。巻き戻しを行うコードはWindows内にあり、throwによって発生した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
88
Hans Passant

__try/__exceptはキャッチSEH(windows generated errors)一般的な例外をキャッチするためではありません。

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

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

また、finallyはC++標準で指定された構造ではありません。Microsoftコンパイラ拡張

22
Alok Save

__try/__exceptMicrosoft固有 コードを他のコンパイラ(c ++など)でコンパイルしたい場合(または)別のOSで使用しないで、 標準try/catch ステートメント

3
Ioan Paul Pirau