异常处理 - 在离开catch之后会发生什么。

3
所以,假设你捕获了一个异常,然后在catch中写入日志文件说明出现了某个异常。接着你希望程序继续执行,因此你必须确保某些不变量仍处于良好的状态。但是,在通过catch“处理”异常后系统实际上发生了什么?此时堆栈已经展开,那么它如何恢复其状态呢?
6个回答

6
"堆栈展开"意味着在throw和匹配的catch子句之间的所有作用域都被离开,调用这些作用域中所有自动对象的析构函数,就像从函数返回时离开函数作用域一样。
除此之外,没有进行任何其他“特殊”操作,catch子句的作用域是正常的作用域,离开它与离开else子句的作用域没有区别。
如果您需要确保某些不变量仍然成立,则需要以线程安全的方式编写更改它们的代码。 Dave Abrahams编写了关于不同异常安全级别的经典文章,您可能想阅读。基本上,您将必须始终使用RAII以确保在抛出异常时处于安全状态。

2

在捕获异常后,确保应用程序恢复到稳定状态是由您来负责的。通常,这可以通过“忘记”产生异常的任何操作或更改,并在更高的级别上重新开始来实现。

这包括确保释放在导致异常的事件链中分配的任何资源。在C++中,确保这一点的标准习惯用法是RAII

更新

例如,如果在Web服务器中处理请求时发生错误,则会在某个较低级别的函数中生成异常,该异常在较高级别的类(可能直接在顶级请求处理程序中)中被捕获。通常最好的做法是回滚所有已经完成的更改并释放与实际请求相关的任何已分配资源,然后向客户端返回适当的错误消息。更改可能包括数据库事务、文件写入等-必须以异常安全的方式实现所有这些内容。数据库通常具有内置的事务来处理此类问题;对于其他资源,可能会更加棘手。


你能给一个简单的例子来说明如何实际操作吗?因为在一个大型应用程序中,这似乎并不那么简单... - Tony The Lion
@Tony,我添加了一个例子,希望能帮到你。 - Péter Török

2

只有在 try 内创建的对象才会在程序异常处理时被销毁。你需要编写程序以使其在发生异常时保持状态一致,这就是所谓的 异常安全

C++ 不会关心这些 - 它会在异常处理时回滚栈,然后将控制权传递到相应的 catch 中,然后流程继续正常执行。


1

这取决于应用程序。有几个级别的异常安全性。你所描述的级别很难在整个应用程序中实现。

然而,某些代码片段可以通过使用RAII等技术和巧妙地排序操作序列来实现“故障透明”。例如,我可以想象一段查询多个URL以获取数据的代码:当一个URL“抛出”时,仍然可以处理其余的URL。或者可以重试...


0

如果每个函数都有异常处理,你可以在下一个更高的级别上恢复,但这相当复杂。实际上,我主要使用异常来尽可能接近源头地检测错误,但不用它们来恢复执行。

另一方面,如果有可预测的错误,可以设计方案来处理它们,但对我来说,异常被视为例外情况,所以我倾向于优雅地退出,并在日志文件中提供良好的提示。JM2CW


0

不行。在C++中,异常是不可恢复的。大多数现代语言也是如此;一些最早支持异常的语言支持可恢复异常,并发现这不是一个好主意。

如果你想从某个特定点恢复,你必须在那里放置try/catch块。如果你只想记录并继续执行,那么就不要首先抛出异常。


继续与终止是此视频中的众多有趣话题之一。 - fredoverflow

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