C++, __try 和 try/catch/finally

发布于 2024-11-29 07:03:49 字数 112 浏览 2 评论 0原文

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

I'm wondering a bit about C++ try/catch/finally blocks. I've seen these commands with two underscores like __try. But MVSC 2010 projects also run without the underscores. So when do you need these underscores?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

゛清羽墨安 2024-12-06 07:03:49

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

为了与 C++ 标准保持一致,throwcatch 关键字仅抛出和捕获 C++ 异常。 MSVC编译器对应的SEH异常代码是0xe06d7363。最后 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++ 中没有等效项,但在其他语言中并不罕见。

正如评论中指出的,所有这些都没有很好的记录。证据就在布丁里。这是一个您可以使用的示例程序。它演示了 SEH 异常如何仍然允许调用 C++ 析构函数,前提是您使用 /EHa 进行编译,以及 C++ 异常如何在 SEH 之上实现。需要 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

On Windows, exceptions are supported at the operating system level. Called Structured Exception Handling (SEH), they are the rough equivalent to Unix signals. Compilers that generate code for Windows typically take advantage of this, they use the SEH infrastructure to implement C++ exceptions.

In keeping with the C++ standard, the throw and catch keywords only ever throw and catch C++ exceptions. The corresponding SEH exception code for the MSVC compiler is 0xe06d7363. The last 3 bytes are the ASCII code for "msc".

Unifying it with the operating system support also means that C++ destructors will be called during stack unwinding for an SEH exception. The code that does the unwinding is inside Windows and treats the SEH raised by a throw the exact same way as any SEH. However, the Microsoft compiler has an optimization that tries to avoid generating the code required that ensures that destructors are called in all cases. If it can prove that there's no throw statement inside the scope block that controls the object's lifetime then it skips the registration code. This is not compatible with asynchronous SEH exceptions, you should use the /EHa compile option to suppress this optimization if you intend to catch SEH exceptions.

There are a lot of SEH exception types. The ones that can be generated by the operating system are listed in the ntstatus.h SDK header file. In addition, you might interop with code that uses SEH to implement their own exception handling, they will use their own exception code. Like .NET, managed exceptions use the 0xe0434f4d ("com") exception code.

To catch SEH exceptions in a C++ program, you must use the non-standard __try keyword. The __except keyword is analogous to the C++ catch keyword. It has more capabilities, you specify an exception filter expression that determines whether or not an active exception should be caught. Anything is possible, but you typically only look at the passed exception information to see if you're interested in handling it. The __finally keyword lets you write code that runs after the exception is handled. No equivalent for that in C++ but not uncommon in other languages.

All of this is fairly poorly documented as pointed out in the comments. The proof is in the pudding. Here's an example program that you can play with. It demonstrates how SEH exceptions still allows for C++ destructors to be called, provided you compile with /EHa and how C++ exceptions are implemented on top of SEH. MSVC compiler required, run with Ctrl+F5 to avoid the debugger being helpful:

#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;
}

Output:

Filtering c0000005
destructed
caught
Filtering e06d7363
destructed
caught
小耗子 2024-12-06 07:03:49

__try / __ except 用于捕获 SEH(Windows 生成的错误) 不适用于捕获一般异常。

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

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

另外,< code>finally 不是 C++ 标准指定的构造,它适合您,因为它是 Microsoft 编译器扩展

__try / __except is for catching SEH (windows generated errors) not for catching general exceptions.

try / catch is what the C++ standard specifies for handling general C++ exceptions.

For the standard C++ code you write you should always use try/ catch and not __try / __except

Also, finally is not C++ Standard specified construct, It works for you because it is a Microsoft compiler extension.

网名女生简单气质 2024-12-06 07:03:49

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

__try/__except is Microsoft specific If you want your code to be compilable with other compilers (for examplec g++) (or) in another OS avoid using them, and stick with the standard try/catch statements

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文