异常处理(EH)似乎是当前的标准,并且通过搜索网络,我找不到任何尝试改进或取代它的新颖想法或方法(当然,存在一些变化,但没有新颖性)。
尽管大多数人似乎忽略了它,或者只是接受它,但EH有一些巨大的缺点:代码中看不到例外,它创造了许多可能的退出点。乔尔在软件上写了article about it。与goto
的比较非常吻合,这让我再次想到了EH。
我尽量避免使用EH,只使用返回值,回调或任何符合目的的东西。但是当你必须编写可靠的代码时,你现在不能忽略EH:它从new
开始,它可能会抛出一个异常,而不是仅仅返回0(就像过去一样)。这使得任何一行C++代码都容易受到异常的影响。然后,C++基础代码中的更多地方会抛出异常...... std lib会执行此操作,依此类推。
这感觉就像走在摇摇欲坠的理由上。所以,现在我们被迫关心异常!
但它很难,它真的很难。你必须学会写异常安全的代码,即使你有一些经验,仍然需要仔细检查任何一行代码才能安全!或者你开始在任何地方放置try / catch块,这会混淆代码,直到达到不可读状态。
EH取代了旧的清晰的确定性方法(返回值..),它只有一些但易于理解和易于解决的缺点,并在代码中创建了许多可能的退出点,并且如果您开始编写捕获异常的代码(您在某些时候被迫做),然后它甚至通过你的代码创建了许多路径(在catch块中的代码,想想你需要日志工具而不是std :: cerr的服务器程序..)。 EH有优势,但这不是重点。
我的实际问题:
- 你真的写了异常安全的代码吗?
- 你确定你最后一次“准备就绪”的代码是异常安全吗?
- 你甚至可以肯定,它是吗?
- 您是否知道和/或实际使用可行的替代方案?
没有找到相关结果
已邀请:
13 个回复
phic
赞同来自:
我尝试了最好的编写异常安全的代码,是的。 这意味着我要注意哪些线可以投掷。不是每个人都可以,并且牢记这一点至关重要。关键是要考虑并设计您的代码以满足标准中定义的异常保证。 可以编写此操作以提供强大的异常保证吗?我必须满足于基本的吗?哪些行可能会抛出异常,如何确保它们不会破坏对象?
ciste
赞同来自:
在C++中编写异常安全的代码并不是要使用大量的try {} catch {}块。它是关于记录代码提供什么样的保证。 我建议阅读Herb Sutter的Guru Of The Week系列,特别是分期59,60和61。 总而言之,您可以提供三种级别的异常安全性:
cet
赞同来自:
首先(正如Neil所说),SEH是微软的结构化异常处理。它与C++中的异常处理类似但不完全相同。实际上,如果你想在Visual Studio中使用它,你必须使用enable C++ Exception Handling - 默认行为并不能保证在所有情况下都会销毁本地对象!在任何一种情况下,异常处理并不是真的更难,它只是不同。 现在为您提出实际问题。
是。在所有情况下,我都在争取异常安全代码。我使用RAII技术进行资源范围访问(例如,boost::shared_ptr用于内存,boost::lock_guard用于锁定)。通常,RAII和scope guarding技术的一致使用将使异常安全代码更容易编写。诀窍是了解存在的内容以及如何应用它。 不,这是安全的。我可以说,由于几年的24/7活动中的异常,我没有看到过程故障。我不希望完美的代码,只是编写良好的代码。除了提供异常安全性之外,上述技术还保证了使用try
/catch
块几乎无法实现的正确性。如果您正在捕获最高控制范围(线程,进程等)中的所有内容,那么您可以确保在面对异常时继续运行(most of the time)。在没有try
/catch
块的情况下,相同的技术也可以帮助您在异常情况下继续正常运行。 是。您可以通过彻底的代码审核来确定,但没有人真正做到这一点吗?定期的代码审查和细心的开发人员在很长的路要走。 多年来我尝试了一些变化,例如在高位编码状态(ala HRESULTs)或可怕的setjmp() ... longjmp()黑客。这两种方式在实践中都以完全不同的方式分解。最后,如果你养成了应用一些技巧并仔细考虑在异常情况下可以实际执行某些操作的习惯的习惯,那么最终会得到非常安全的可读代码。您可以按照以下规则进行总结:
try
/catch
new
或delete
std::sprintf
,snprintf
和一般数组 - 使用std::ostringstream
格式化并用std::vector
替换数组和std::string
menim
赞同来自:
在“任何行都可以抛出”的假设下,不可能编写异常安全的代码。异常安全代码的设计主要依赖于您应该在代码中期望,观察,遵循和实现的某些合同/保证。保证永不抛出的代码是绝对必要的。还有其他种类的例外保证。 换句话说,创建异常安全代码在很大程度上是程序设计的问题,而不仅仅是普通编码问题。
dodit
赞同来自:
人们做了很多(我甚至会说最多)。 关于异常真正重要的是,如果你不编写任何处理代码 - 结果是非常安全和良好的行为。太急于恐慌,但安全。 你需要在处理程序中积极地犯错以获得不安全的东西,并且只有catch(...){}将与忽略错误代码进行比较。
uculpa
赞同来自:
nsit
赞同来自:
一般来说,EH很好。但是C++的实现并不是很友好,因为很难说你的异常捕获覆盖有多好。例如,Java使这很容易,如果你不处理可能的异常,编译器往往会失败。
nin
赞同来自:
我们中的一些人已经使用例外超过20年。例如,PL / I有它们。它们是一种新的危险技术的前提似乎对我来说是个问题。
nodio
赞同来自:
gminus
赞同来自:
抛开SEH和C++异常之间的混淆,您需要意识到可以随时抛出异常,并在编写代码时考虑到这一点。对异常安全的需求在很大程度上推动了RAII,智能指针和其他现代C++技术的使用。 如果您遵循完善的模式,编写异常安全的代码并不是特别困难,事实上它比编写在所有情况下都能正确处理错误返回的代码更容易。
eenim
赞同来自:
我非常喜欢使用Eclipse和Java(Java新手),因为如果你缺少一个EH处理程序,它会在编辑器中抛出错误。这使得忘记处理异常变得更加困难...... 此外,使用IDE工具,它会自动添加try / catch块或其他catch块。
frerum
赞同来自:
我们中的一些人更喜欢像Java这样的语言,它迫使我们声明方法抛出的所有异常,而不是像C++和C#那样使它们不可见。 如果正确完成,异常优于错误返回代码,如果没有其他原因,您不必手动向上传播失败的调用链。 话虽这么说,低级API库编程应该可以避免异常处理,并坚持错误返回代码。 根据我的经验,用C++编写干净的异常处理代码很困难。我最终使用了
new(nothrow)
。oqui
赞同来自:
内容太长未翻译