C++, __try and try/catch/finally

C++, __try and try/catch/finally

本文关键字:try finally catch and C++      更新时间:2023-10-16

我对c++的try/catch/finally块有点疑惑。我见过这些带有两个下划线的命令,比如__try。但是MVSC 2010项目也没有下划线。什么时候需要下划线呢?

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

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

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

有很多SEH异常类型。操作系统可以生成的SDK在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

__try/__except用于捕获SEH (windows生成的错误)而不是用于捕获一般异常。

try/catch是c++标准为处理一般c++异常所指定的。

对于你写的标准c++代码,你应该总是使用try/catch而不是__try/__except

此外,finally不是c++标准指定的构造,它为您工作,因为它是一个微软编译器扩展

__try/__except是Microsoft专用的。如果您希望您的代码可以在其他编译器(例如g++)(或)在其他操作系统中编译,请避免使用它们,并坚持使用标准的try/catch语句