48

每个 C++ 开发人员都应该了解结构化异常的哪些要点?

4

5 回答 5

46

它们是 Unix 信号的 Win32 等价物,可让您捕获 CPU 异常,例如访问冲突、非法指令、除以零。

使用正确的编译器选项(Visual C++ 的 /EHa),C++ 异常使用与堆栈展开相同的机制,适用于 C++(用户)异常和 SEH(OS)异常。

与 C++ 异常不同,SEH 没有类型,但都共享相同的数据结构,该数据结构具有异常代码(原因)以及有关故障代码和故障时 CPU 寄存器保存的附加信息。有关这方面的更多详细信息,请参见GetExceptionCodeGetExceptionInformation

此外,SEH 具有“第一机会”处理,它允许您在展开破坏所有局部变量之前记录或以其他方式处理异常。

于 2010-05-06T17:09:06.337 回答
37

我最近遇到了一个由 SEH 间接引起的问题,特别是因为我认为每个开发人员都应该知道的 SEH 的一个特性:

使用 SEH 时不会调用析构函数,因此如果您的析构函数中有清理代码,它将不会被清理。

我们的问题是由一个关键部分引起的,该部分由构造函数中的 Lock 和析构函数中的 Unlock 对象包装。

我们遇到了死锁情况,无法弄清楚原因,经过大约一周的代码挖掘和转储和调试,我们终于明白这是因为 COM 处理了一个异常并导致关键部分保持锁定. 我们在项目属性中更改了 VS 中的编译标志,它告诉它甚至为 SEH 运行析构函数,从而解决了问题。

因此,即使您可能没有在代码中使用 SEH,您也可能正在使用可以使用的库(如 COM),这可能会导致意外行为。

于 2010-10-15T12:28:22.417 回答
25

他们应该知道它们不是标准 C++ 的一部分——它们是 Microsoft 发明的,可以在 C++ 以外的语言中使用。

于 2010-05-06T17:08:12.720 回答
24

Win32™ 结构化异常处理深度速成课程

那篇文章是了解 SEH 速度的参考资料。13年后,依然是最好的。

MSDN 上有一个专门讨论SEH 与 C++ 异常处理差异的主题。

如果正在讨论 SEH,C++ 开发人员应该知道的一些事情:

编写 C/C++ SEH异常处理程序

__try 
{
   // guarded code
}
__except ( expression )
{
   // exception handler code
}

不是C++ 异常处理,是用于挂钩直接 inot SEH 的 MS 特定扩展。它的工作方式与您的普通 C++ 异常非常不同。您需要对 SEH 有很好的了解才能使用这些。

编写 C/C++ SEH终止处理程序

__try {
   // guarded code
}
__finally {
   // termination code
}

与 SEH 处理程序相同,不要将其与 C++ 异常语义混淆。您需要对 SEH 有一个很好的了解。

_set_se_translator:这是在使用异步异常时将 SEH 异常转换为 C++ 类型异常的函数/EHa

最后,个人意见:C++ 开发人员应该了解 SEH 吗?在您的第一个菜鸟.ecxr之后,您会明白,当事态严重时,C++ 异常只是为您提供方便的一种错觉。唯一发生的事情是 SEH。

于 2010-05-06T21:22:09.327 回答
1

重要的一点是知道何时使用 SEH 以及何时使用标准 C++ 异常。首先,只选择一个系统——混合系统往往会出现问题,需要对两者都有深入的了解才能很好地实施。其次,在高层次上,SEH 不限于 C++,而标准 C++ 异常也不限于 Windows。如果这不能决定您的决定,请选择标准例外,除非它们不充分(有关 SEH 可以做什么的更多详细信息,请参阅其他答案)。

微软文档(2018 年 8 月 13 日)的引述支持这一结论。

结构化异常处理 (SEH) 是 Microsoft 对 C 的扩展,用于优雅地处理某些异常代码情况,例如硬件故障。尽管 Windows 和 Microsoft C++ 支持 SEH,但我们建议您使用 ISO 标准 C++ 异常处理,因为它使您的代码更加可移植和灵活。尽管如此,为了维护现有代码或特定类型的程序,您可能仍然必须使用 SEH。

为什么扩展的作者会建议在大多数情况下不要使用它?大概是因为扩展是为 C 编写的,而当前上下文是 C++。这些语言是相似的,因此将 SEH 移植到 C++ 作为附带好处可能很容易,即使只有“特定类型的程序”会真正受益。(或者可能是其他一些原因;也许移植是在 C++ 标准化之前开始的。历史变得令人费解。)

于 2019-06-14T15:51:59.863 回答