异常处理(EH)似乎是当前的标准,通过搜索网络,我找不到任何新的想法或方法来改进或取代它(好吧,存在一些变化,但没有什么新奇的)。

尽管大多数人似乎忽略了它或只是接受它,EH有一些巨大的缺点:异常对代码是不可见的,它创建了许多许多可能的退出点。软件的Joel写了一篇关于它的文章。与goto的对比非常完美,这让我再次思考EH。

我尽量避免EH,只使用返回值,回调或任何符合目的的东西。但是,当您必须编写可靠的代码时,现在就不能忽略EH了:它从new开始,可能会抛出异常,而不只是返回0(就像以前一样)。这使得几乎每一行c++代码都容易出现异常。然后在c++基本代码中抛出异常的地方更多……STD lib可以这样做,等等。

这感觉就像在摇摇欲坠的地面上行走。因此,现在我们不得不关注异常!

但这很难,真的很难。你必须学会编写异常安全的代码,即使你有一些这方面的经验,仍然需要仔细检查每一行代码的安全性!或者您开始到处放置try/catch块,这会使代码变得混乱,直到达到不可读的状态。

EH replaced the old clean deterministical approach (return values..), which had just a few but understandable and easily solveable drawbacks with an approach that creates many possible exit points in your code, and if you start writing code that catches exceptions (what you are forced to do at some point), then it even creates a multitude of paths through your code (code in the catch blocks, think about a server program where you need logging facilities other than std::cerr ..). EH has advantages, but that's not the point.

我真正的问题是:

你真的写异常安全的代码吗? 您确定最后的“生产就绪”代码是异常安全的吗? 你能确定这是真的吗? 你知道和/或实际上使用有效的替代方法吗?


当前回答

不过,我真的很喜欢使用Eclipse和Java (Java新手),因为如果缺少EH处理程序,它会在编辑器中抛出错误。这使得忘记处理异常变得更加困难……

另外,使用IDE工具,它会自动添加try / catch块或另一个catch块。

其他回答

我们中的一些人使用例外已经超过20年了。例如PL/I就有。在我看来,它们是一种危险的新技术的前提是值得怀疑的。

很多人(我甚至会说大多数人)都这么做。

关于异常,真正重要的是,如果你不写任何处理代码,结果是完全安全和良好的。太急于慌张,反而安全。

您需要在处理程序中主动地犯错误以获得不安全的东西,并且只有catch(…){}将与忽略错误代码相比。

Do you really write exception safe code? [There's no such thing. Exceptions are a paper shield to errors unless you have a managed environment. This applies to first three questions.] Do you know and/or actually use alternatives that work? [Alternative to what? The problem here is people don't separate actual errors from normal program operation. If it's normal program operation (ie a file not found), it's not really error handling. If it's an actual error, there is no way to 'handle' it or it's not an actual error. Your goal here is to find out what went wrong and either stop the spreadsheet and log an error, restart the driver to your toaster, or just pray that the jetfighter can continue flying even when it's software is buggy and hope for the best.]

首先(正如Neil所说),SEH是微软的结构化异常处理。它类似于c++中的异常处理,但不完全相同。事实上,如果你想在Visual Studio中使用它,你必须启用c++异常处理——默认行为并不能保证在所有情况下局部对象都被销毁!在任何一种情况下,异常处理并不难,只是不同而已。

现在轮到你的实际问题了。

你真的写异常安全的代码吗?

是的。我努力在所有情况下都使用异常安全的代码。我提倡使用RAII技术对资源进行作用域访问(例如,boost::shared_ptr用于内存,boost::lock_guard用于锁定)。一般来说,RAII和范围保护技术的一致使用将使异常安全代码的编写更加容易。诀窍在于了解存在的东西以及如何应用它。

您确定最后的“生产就绪”代码是异常安全的吗?

No. It is as safe as it is. I can say that I haven't seen a process fault due to an exception in several years of 24/7 activity. I don't expect perfect code, just well-written code. In addition to providing exception safety, the techniques above guarantee correctness in a way that is near impossible to achieve with try/catch blocks. If you are catching everything in your top control scope (thread, process, etc.), then you can be sure that you will continue to run in the face of exceptions (most of the time). The same techniques will also help you continue to run correctly in the face of exceptions without try/catch blocks everywhere.

你能确定这是真的吗?

是的。你可以通过彻底的代码审核来确定,但没有人真的这么做,不是吗?不过,定期的代码审查和细心的开发人员要达到这个目标还有很长的路要走。

你知道和/或实际上使用有效的替代方法吗?

多年来,我尝试了一些变化,比如在上面的位编码状态(ala HRESULTs)或可怕的setjmp()…longjmp()攻击。这两种方法在实践中都是行不通的,尽管是以完全不同的方式。


最后,如果您养成了应用一些技术的习惯,并仔细考虑在哪里可以实际执行一些响应异常的操作,那么您最终将得到非常可读且异常安全的代码。你可以通过以下规则来总结:

只有当您可以对特定异常执行某些操作时,才希望看到try/catch 您几乎不希望在代码中看到原始的new或delete 一般避免使用std::sprintf、snprintf和数组——使用std::ostringstream进行格式化,并使用std::vector和std::string替换数组 如果有疑问,在开发自己的Boost或STL之前,先看看它的功能

我只能建议你学习如何正确地使用异常,如果你打算用c++写代码,忘记结果代码。如果您想要避免异常,您可能会考虑使用另一种语言来编写,这种语言要么没有异常,要么使异常安全。如果你真的想学习如何充分利用c++,可以阅读一些Herb Sutter、Nicolai Josuttis和Scott Meyers的书。

如果假设“任何行都可以抛出”,就不可能编写异常安全的代码。异常安全代码的设计主要依赖于某些契约/保证,你应该在你的代码中期望、观察、遵循和实现这些契约/保证。拥有保证永不抛出的代码是绝对必要的。还有其他类型的异常保证。

换句话说,创建异常安全代码在很大程度上是程序设计的问题,而不仅仅是简单的编码问题。