每个C ++开发人员都应该知道哪些关于结构化异常的重要观点?
答案 0 :(得分:39)
它们是Win32,相当于Unix信号,让你捕获CPU异常,例如访问违规,非法指令,除以零。
使用正确的编译器选项(/ EHa for Visual C ++),C ++异常使用相同的机制,因为堆栈展开适用于C ++(用户)异常和SEH(OS)异常。
与C ++异常不同,SEH不是类型化的,但它们共享相同的数据结构,该结构具有异常代码(原因)以及有关哪些代码出现故障以及CPU在寄存时记录的内容的附加信息。有关详细信息,请参阅GetExceptionCode
和GetExceptionInformation
。
此外,SEH具有“第一次机会”处理,允许您在展开之前记录或以其他方式处理异常破坏所有局部变量。
答案 1 :(得分:29)
我最近有一个由SEH间接引起的问题,特别是因为我认为每个开发人员都应该注意SEH的一个特性:
当使用SEH时,不会调用析构函数,因此如果在析构函数中有清理代码,则不会清除它。
我们的问题是由一个关键部分引起的,该部分由一个在构造函数中使用Lock并在析构函数中解锁的对象包装。
我们遇到了死锁的情况,无法弄清楚原因,经过大约一周的挖掘代码,转储和调试后,我们终于明白这是因为有一个异常由COM处理并导致了Critical部分保持锁定。 我们在项目属性中更改了VS中的编译标志,告诉它甚至为SEH运行析构函数,这解决了问题。
因此,即使您可能不在代码中使用SEH,您可能正在使用一个(如COM)的库,这可能会导致意外行为。
答案 2 :(得分:24)
他们应该知道它们不是标准C ++的一部分 - 它们是Microsoft的发明,可以用于C ++以外的语言。
答案 3 :(得分:20)
A Crash Course on the Depths of Win32™ Structured Exception Handling
该文章是关于加快SEH速度的 参考。 13年后,仍然是最好的。
MSDN上有SEH vs. C++ Exception Handling Differences专用主题。
如果正在讨论SEH,C ++开发人员应该知道的一些事情:
编写C / C ++ SEH Exception Handlers:
__try
{
// guarded code
}
__except ( expression )
{
// exception handler code
}
这是不 C ++异常处理,是用于直接连接SEH的MS特定扩展。它的工作方式与普通的C ++异常完全不同。您需要很好地了解SEH才能使用它们。
编写C / C ++ SEH Termination Handlers:
__try {
// guarded code
}
__finally ( expression ) {
// termination code
}
与SEH处理程序相同,不要将其与C ++异常语义混淆。你需要很好地了解SEH。
_set_se_trasnlator
:这是在使用异步异常时将SEH异常转换为C ++类型异常的函数/EHa。
最后,个人意见:C ++开发人员应该知道SEH吗?在你的第一个新人.ecxr之后,你会明白当推动C ++时,异常只是为了你的方便而提供的错觉。唯一发生的事情是SEH。
答案 4 :(得分:1)
重要的一点是知道何时使用SEH以及何时使用标准C ++异常。首先,仅选择一个系统-混合系统往往会出现问题,需要对这两个系统都有深刻的理解才能很好地实施。其次,从总体上讲,SEH不仅限于C ++,而标准的C ++例外并不限于Windows。如果这不能决定您的决定,请选择标准例外,除非它们不足够(有关SEH可以做什么的更多详细信息,请参阅其他答案)。
Microsoft's documentation(日期为2018年8月13日)中的一句话支持了这一结论。
结构化异常处理(SEH)是Microsoft对C的扩展,可以优雅地处理某些特殊的代码情况,例如硬件故障。尽管Windows和Microsoft C ++支持SEH,但我们建议您使用ISO标准的C ++异常处理,因为这会使您的代码更加可移植和灵活。但是,要维护现有代码或特定类型的程序,您仍然可能必须使用SEH。
为什么扩展名的作者建议在大多数情况下不使用它?大概是因为扩展是为C编写的,当前上下文是C ++。这些语言是相似的,因此将SEH移植到C ++作为附带好处可能很容易,即使只有“特定类型的程序”才能真正受益。 (或其他可能的原因;也许是在C ++标准化之前就开始了移植。令人费解的历史。)