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

mar*_*tin 42 c++ exception-handling finally try-catch

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

Han*_*ant 88

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

为了与C++标准保持一致,throwcatch关键字只能抛出并捕获C++异常.MSVC编译器的相应SEH异常代码是0xe06d7343.最后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编译以及如何在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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

Filtering c0000005
destructed
caught
Filtering e06d7363
destructed
caught
Run Code Online (Sandbox Code Playgroud)

  • 嗯,非常形而上学,难道我们都不只是蝴蝶认为是人类吗?这只蝴蝶认为他在过去的15年里一直在用C++编写机器控制软件.让SEH崩溃的机器对我们的客户来说并不是很受欢迎.不要太担心downvote,你的答案很受欢迎,你可能会得到它的徽章.另一种感知. (8认同)
  • 我不知道,__try的行为只记录在C编译器中.在/ EHa的文档中有一点点但是它还不够.如果文档一直是恒星,那就不会有任何SO :) (5认同)
  • 不要误解我的评论,我向你致以崇高的敬意,自从我开始参与这里以来,你已经看到了来自你的优秀答案。至于downvote,我不会为它出汗,但是如果我或其他任何人没有从downvote中学到任何东西,那么它对任何人都没有好处。我只是想为您提供的相互矛盾的观点寻求书面证据或合乎逻辑的解释,因为我必须自己相信才能纠正我可能有的错误理解。在任何情况/情况下,我都无意冒犯,所以请不要接受任何。 (2认同)
  • 我参加这个聚会迟到了,但这篇文章是最后的推动力,它让我们对处理 SEH 异常有了初步的了解,我们既可以保护我们的客户免受崩溃的影响,又可以取回一些有关故障所在的有用信息。汉斯,谢谢你穿过丛林,让阳光照进来。 (2认同)

Alo*_*ave 22

__try/ __except用于捕获SEH(窗口生成的错误),而不是用于捕获常规异常.

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

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

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

  • 尝试/捕获不会处理SEH.使用`/ EHa`(是和SEH异常)时,try/catch将同时处理:C++和SEH异常.缺点是`catch(...)`将处理SEH,但你不能知道异常代码.使用`EHa`时将调用析构函数.`try`和`__try`都不能混合在同一个函数中.因此最好有两个函数(一个调用另一个):一个处理`try`和另一个处理`__try`(没有`/ EHa`) (8认同)

Ioa*_*rau 3

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

  • 这是正确的,尽管这样您将失去捕获 Windows 的 SEH 异常的能力。这就是您需要非标准处理的时候。 (2认同)