【问题标题】:Difference between a C++ exception and Structured ExceptionC++ 异常和结构化异常之间的区别
【发布时间】:2011-04-16 17:51:48
【问题描述】:

有人可以解释 C++ 异常和 MFC 中结构化异常之间的区别吗?

【问题讨论】:

    标签: c++ exception mfc


    【解决方案1】:

    这是一个繁重的 MSVC++ 实现细节,但在 Windows 上,C++ 异常也是 SEH 异常。异常代码为 0xE04D5343(最后三个字节 = 'MSC')。并且所有常规 SEH 支持都用于展开堆栈、运行自动清理代码并过滤异常以便选择正确的 catch 子句。作为demonstrated here

    在过滤器表达式中获取抛出的异常对象是 CRT 添加的管道,超出了 SEH 提供的范围,因为它是特定于 C++ 的,所以必然如此。

    另一个实现细节是 /EH 编译器设置。默认值 (/EHsc) 允许编译器优化生成的代码并抑制运行自动清理所需的异常过滤器。如果它可以看到所有发出的 C++ 代码都不会引发异常。要自动清除 SEH 异常,您必须使用 /EHa 进行编译,以便抑制这种优化。

    将 C++ 异常与 SEH 结合的一种策略是使用 _set_se_translator(),以便您可以将 SEH 异常转换为 C++ 异常。尽管捕获 SEH 异常通常并不明智,但它们几乎总是令人讨厌的。您通常倾向于使用 __try/__catch,如链接答案所示。

    【讨论】:

    • __try/__except 块会捕获所有 SEH 异常以及所有 C++ 异常吗?
    • 另外需要注意的是,根据 MSDN,_set_se_translator() 只会在堆栈上具有 try 块的每个函数调用中调用一次,并且必须基于每个线程进行设置。跨度>
    • 这个和道格的答案是唯一可以接受的答案;其他人没有明确指出 C++ 异常只是添加的功能和 C++ 抽象,它运行在 Windows 内核中的底层异常处理机制之上,这基本上是 SEH。
    • 关键要知道的是,C++异常只捕获抛出的对象,不会捕获段错误之类的运行时错误,只能使用SEH异常过滤器来捕获这些,最终会有一个SEH UnhandledExceptionFilter在线程栈的基函数处
    【解决方案2】:

    你实际上有三种机制:

    • C++ 异常,由编译器实现 (try/catch)
    • 结构化异常处理 (SEH),由 Windows (__try / __except) 提供
    • MFC 异常宏(TRYCATCH - 建立在 SEH / C++ 异常之上 - 另见 TheUndeadFish 的评论)

    C++ 异常通常保证在堆栈展开期间自动清理(即运行本地对象的析构函数),而其他机制则不能。

    C++ 异常仅在显式抛出时发生。许多操作可能会出现结构化异常,例如由于未定义的行为、向 API 传递无效指针、卸载内存映射文件的后备存储等等。

    MFC 确实引入了异常宏来支持异常,即使编译器没有实现它们。

    【讨论】:

    • 出于好奇,MFC 是否曾打算在 VC++ 以外的任何编译器上工作?
    • C++ 异常不需要保证清理。使用 /EHa 编译。
    • MFC 确实在 Watcom C/C++ 10 上工作。不知何故。没有巫师之类的东西。
    • @Hans - 嗯,真的吗? /EHa 与 /EHs 仅影响结构化异常是否被 C++ 异常处理程序捕获。我很确定 C++ 标准 保证 清除了 C++ 异常(让这个实现定义没有意义,因为必要的代码会根本不同)。
    • Wile MFC 的异常过去使用不同的方法(我认为在 VC 支持 C++ 异常之前),MFC 的异常现在建立在 C++ 异常之上。事实上,从 MFC 宏转换为 C++ 的 try/catch 是完全可能的,如下所述:msdn.microsoft.com/en-us/library/19z28s5c.aspx 所以在这一切之下,实际上只有 2 种不同的类型:C++ 异常和 SEH。
    【解决方案3】:

    C++ 异常可以跨平台工作。不幸的是,SEH 将严重限制可移植性(可能跨不同的 Windows 版本除外)。

    SEH 似乎还捕获了许多本机 Windows 异常(如访问冲突、指定了无效句柄)等。

    【讨论】:

      【解决方案4】:

      两者都提供了发生错误时堆栈展开的机制。

      结构化异常由 Windows 提供,并得到内核的支持。如果您执行诸如访问无效内存位置之类的操作,它们会由 Windows 引发。它们还用于支持自动堆栈增长等功能。它们很少单独使用,但 C++、.NET 和类似语言中的语言异常通常是在它们之上构建的。您可以使用 __try__catch 等特殊关键字来处理这些异常。但是,处理它们相对困难且容易出错,因为您可能会破坏自动堆栈扩展等功能,以及可能破坏 C++ 语言异常。

      C++ 异常由 C++ 语言指定。抛出和捕获的数据类型是 C++ 对象(包括原始类型的可能性)。编译器和运行时在底层结构化异常机制之上实现这些。如果您使用 C++ 语言的 trycatchthrow 关键字,这就是您所得到的。

      SEH 异常比 C++ 异常具有更多功能,例如支持恢复,以及所谓的“矢量化”处理程序(接收异常通知,但不一定阻止堆栈展开),但除非您明确知道要使用他们,我会避开他们。如果您的程序做了非法或未定义的事情,它们最常见的用途可能是使用MiniDumpWriteDump 编写故障转储。

      【讨论】:

        【解决方案5】:

        C++ 异常是编程语言 C++ 的一个特性。 结构化异常是 Windows 操作系统的不同概念。 这两个使用相似的语法,但在技术上是不同的。 Windows 结构化异常不仅可用于 C++,还可用于例如与 C.

        有时是统一处理两者的解决方案:在 Windows 应用程序中,您可以提供一个处理函数,该函数捕获所有结构化异常并引发 C++ 异常(由您定义)。

        【讨论】:

          猜你喜欢
          • 2017-05-27
          • 1970-01-01
          • 2019-11-14
          • 2015-05-25
          • 1970-01-01
          • 1970-01-01
          • 2011-11-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多