52

我想知道关于 C++ 的 try/catch/finally 块。我见过这些带有两个下划线的命令,比如 __try。但是 MVSC 2010 项目也可以在没有下划线的情况下运行。那么什么时候需要这些下划线呢?

4

3 回答 3

100

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

为了与 C++ 标准保持一致,throwcatch关键字只会抛出和捕获 C++ 异常。MSVC 编译器对应的 SEH 异常代码为 0xe06d7363。最后 3 个字节是“msc”的 ASCII 码。

将它与操作系统支持统一还意味着在堆栈展开期间将调用 C++ 析构函数以处理 SEH 异常。执行展开的代码位于 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++ 中没有等价物,但在其他语言中并不少见。

正如评论中指出的那样,所有这些都没有得到很好的记录。证据就在布丁里。这是您可以使用的示例程序。它演示了 SEH 异常如何仍然允许调用 C++ 析构函数,前提是您使用 /EHa 进行编译,以及如何在 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(Windows 生成的错误)而不是用于捕获一般异常。

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

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

此外,finally它不是 C++ 标准指定的构造,它适用于您,因为它是Microsoft 编译器扩展

于 2011-08-13T09:08:42.583 回答
4

__try/__except Microsoft特定try/catch

于 2011-08-13T09:08:21.517 回答