Visual C++非托管代码:使用/EHa还是/EHsc来处理C++异常?

22

如果我在未经管理的C++、Visual Studio 2008或更高版本中创建一个新项目,那我应该选择哪种异常处理模型呢?

我知道/EHa选项会导致代码效率降低,并且也会捕获SEH异常, 对吗?

因此,我一直避免使用该选项,通常选择/EHsc选项,这样我只会捕获实际抛出的C ++异常,而不会在catch(...)处理程序中捕获访问冲突和其他结构化异常。如果我的代码中发生访问冲突,我不希望它被catch(...) {}掩盖。

我和其他人一起编写代码时,他们希望catch(...) {}什么也不干,甚至在发生访问冲突时也要这样做,这对我来说似乎是一个非常糟糕的想法。如果由于糟糕的编码而导致错误,您不希望将手指塞进耳朵并大声说“La la la la la!”以便您不必让程序崩溃吗?实际上,如果由于编码错误而现在处于不良状态,则真的希望代码继续运行吗?

因此,我的总体想法是,/EHa会创建更大/更慢的代码,并允许程序员逃避编写代码,即使存在致命错误,它也将继续以未定义的状态运行。

顺便说一下,我谈论的是应用程序和服务代码,这是我们大部分时间编写的内容。而不是低级设备驱动程序或其他类似的东西。

请发表您的想法。

2个回答

23
/EHa有两个作用。首先,它抑制了一种优化,即省略异常过滤器,如果代码分析器看不到可能引发C++异常的代码,则自动调用本地类变量的析构函数。这使得堆栈展开对于任何类型的异常都是安全的,而不仅仅是C++异常。这些异常过滤器的开销在x86平台上是时间,在x86和x64平台上是空间。
是的,它还改变了catch(...)的行为,现在它也会过滤任何SEH异常,而不仅仅是C++异常。这确实是一个赌博,因为你可以捕获所有真正恶心的异步硬件异常。尽管我个人认为捕获所有C++异常也很难被辩解,但你仍然只有模糊的概念,程序状态到底发生了多少变化以及为什么会失败。
现实情况是,您需要切换到使用__try/__except,以便编写自己的异常过滤器并避免捕获坏的异常。C++异常的异常代码为0xe04d5343(“MSC”)。使用_set_se_translator()也是另一种方法。

很好的回答,您能进一步阐述“这些异常过滤器的开销在x86上是时间,在x86和x64上都是空间”的部分吗?更具体地说,为什么在x64上没有时间开销? - Weipeng
2
x64 使用查找表将异常地址映射到捕获处理程序,该表在编译时构建。x86 在 try 块入口处将处理程序地址推送到堆栈上。 - Hans Passant

7
我使用 /EHa 是因为它与 .NET 互操作性更加安全,而 /EHsc 可能不安全;例如,请参见 Destructors not called when native (C++) exception propagates to CLR component

然而,如果对于特定的代码段,额外的性能真的很重要并且您不需要 .NET(或其他任何东西)兼容性,那么当然,/EHsc 听起来很好。

无论是 /EHsc 还是 /EHa 都无法捕获大多数内存错误,因此使用它们捕获访问冲突是一件无望的事情。


3
无论什么情况下都不应该尝试捕获访问冲突。 - Billy ONeal
1
那是我的理解...但我有人写 catch(...){},如果选择了 /EHa,那么我认为它会掩盖访问冲突。捕获 (...) { cleanup_stuff; throw; } 是一回事,但即使在这种情况下,如果捕获到的是访问冲突,你确定 cleanup_stuff 能够正常工作吗?你处于糟糕的状态,所以我认为程序最好在那里崩溃。 - Fauxcuss
4
我正在开发一个客户端/服务器系统,当服务器出现异常(最好是任何类型的异常,包括访问冲突),我希望在允许服务器线程崩溃之前将异常消息发送到客户端。否则,服务器将停止响应。 - Jeff B
3
EHa 绝对是您需要在可靠性至关重要的服务等方面使用的东西。虽然讨论访问违规使问题听起来不太可能,但不要忘记除以零可能会使您的服务崩溃! - Nick Westgate
@NickWestgate 完全同意,在高可用性服务中,有时候通过适当的接口隔离不太可靠的代码部分并捕获所有出现问题的情况(包括除以零)是不难的,同时仍然可以很好地了解程序的状态。 - Weipeng
访问冲突只能由向量处理程序捕获,对吗? - Paul Stelian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接