C ++,__ try和try / catch / finally

时间:2011-08-13 09:05:58

标签: c++ exception-handling try-catch finally

我对C ++ try / catch / finally块有点疑惑。我已经看到这些命令有两个下划线,如__try。但MVSC 2010项目也没有下划线。所以你什么时候需要这些下划线?

3 个答案:

答案 0 :(得分:88)

在Windows上,操作系统级别支持例外。称为结构化异常处理(SEH),它们与Unix信号大致相当。为Windows生成代码的编译器通常会利用这一点,他们使用SEH基础结构来实现C ++异常。

为了与C ++标准保持一致, throw catch 关键字只能抛出并捕获C ++异常。 MSVC编译器的相应SEH异常代码是0xe06d7343。最后3个字节是“msc”的ASCII码。

将其与操作系统支持统一也意味着在堆栈展开期间将为SEH异常调用C ++析构函数。执行展开的代码在Windows中,并以与任何SEH完全相同的方式处理由 throw 引发的SEH。但是,Microsoft编译器有一个优化,它试图避免生成所需的代码,以确保在所有情况下都调用析构函数。如果它可以证明在范围块内没有控制对象生命周期的throw语句,那么它会跳过注册码。这与异步SEH异常不兼容,如果要捕获SEH异常,应使用/ EHa编译选项来抑制此优化。

有很多SEH异常类型。可以由操作系统生成的那些列在ntstatus.h SDK头文件中。此外,您可能与使用SEH实现自己的异常处理的代码互操作,它们将使用自己的异常代码。与.NET一样,托管异常使用0xe0434f4d(“com”)异常代码。

要在C ++程序中捕获SEH异常,必须使用非标准__try关键字。 __except关键字类似于C ++ catch 关键字。它具有更多功能,您可以指定一个异常过滤器表达式,用于确定是否应捕获活动异常。一切皆有可能,但您通常只查看传递的异常信息,看看您是否对处理它感兴趣。 __finally关键字允许您编写在处理异常后运行的代码。在C ++中没有相同的东西,但在其他语言中并不罕见。

正如评论中指出的那样,所有这些都记录得很差。证据就在布丁中。这是一个可以玩的示例程序。它演示了如果使用/ EHa编译以及如何在SEH之上实现C ++异常,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

答案 1 :(得分:22)

__try / __except用于捕获 SEH (windows generated errors) ,而不是用于捕获常规异常。

try / catch是C ++标准指定用于处理一般C ++异常的内容。

对于您编写的标准C ++代码,您应始终使用try / catch而不是__try / __except

此外,finally不是C ++ Standard指定的构造,它适用于您,因为它是 Microsoft compiler extension

答案 2 :(得分:3)

__try/__except is Microsoft specific如果您希望您的代码可以与其他编译器(例如c g ++)(或)在另一个操作系统中编译,请避免使用它们,并坚持使用standard try/catch语句< / p>