首页 > 解决方案 > 什么时候可以通过捕获异常来真正解决问题?

问题描述

事情就是这样。关于异常,我不太了解,对我来说,它们似乎是一个几乎可以工作的构造,但不能干净地使用。

我有一个简单的问题。什么时候捕获异常是解决问题根本原因的有用或必要的组成部分?即,您何时能够编写代码来修复通过异常发出的问题?我正在寻找事实数据或您的经验。

这就是我的意思。一个正常的程序确实有效。如果某项工作由于原因 X 无法完成,则负责完成该工作的函数会抛出异常。但是谁发现异常?在我看来,您可能想要捕获异常的三个原因:

  1. 你抓住它是因为你想改变它的类型并重新抛出它。(当您将机械异常(例如)转换std::out_of_range为业务异常(例如)时会发生这种情况could_not_complete_transaction
  2. 您捕获它是因为您想在中止之前记录它,或者让用户知道问题所在。
  3. 你抓住它是因为你真的知道如何解决这个问题。

我对第 3 点持怀疑态度。我从来没有真正捕获到异常,知道如何解决它。当你得到一个std::out_of_memory,你应该怎么处理它?这不像您可以通过交换操作系统来获得更多内存。这不是您可以解决的问题。不仅如此std::out_of_memory,还有商务舱例外。考虑一个潜在的connection_error异常:除了等待并稍后重试并希望它自行修复之外,您能做些什么来解决这个问题?

现在,公平地说,我确实知道一种情况,其中代码确实捕获了异常并尝试解决问题。我知道某些 Win32 SEH 处理程序会捕获堆栈溢出异常,并尝试通过扩大线程堆栈的大小来解决问题(如果可能的话)。但是,这是可行的,因为 SEH 具有 try-resume 语义,而 C++ 异常没有这些语义(您无法在异常发生时恢复)。

问题的主要部分已经结束。但是,还有一个异常问题,对我来说,这似乎正是您没有解决问题的 catch 子句的原因:捕获异常的代码必须与抛出异常的代码相结合。因为,为了解决问题,它必须具有关于问题原因的领域特定知识。但是当一些库文档说“如果这个函数失败,internal_error就会抛出一个异常”,当我不知道库内部是如何工作的时候,我应该如何解决这个问题呢?

PS:请注意,这不是“异常与错误代码”之类的问题;我很清楚错误代码作为一种错误处理机制很糟糕。他们实际上遇到了我为例外解释过的同样问题。

标签: c++exception

解决方案


我认为您的问题是您将“解决问题”等同于“使程序继续正常运行”。这是思考异常或一般错误处理的错误方式。

任何类型的错误处理代码都不应该是程序内部可以修复的东西。即不应该因为编程错误而输入错误处理逻辑(如捕捉异常)。

如果用户给你一个不存在的文件名,那不是编程错误;这是一个用户错误。如果不返回用户并获取现有文件,则无法“修复”该问题。但是异常确实允许您撤消您尝试执行的操作,将程序恢复到有效状态,然后将发生的情况传达给用户。

Aninvalid_connection同样不是编程错误。与上述不同,它也不一定是用户错误。这是预期能够发生的事情,不同的程序会以不同的方式处理它。有些人会想再试一次。其他人会想要停止并让用户知道。

关键是,因为没有一种方法可以处理这种情况,所以库无法完成。必须将错误提供给库的调用者以弄清楚要做什么。

如果你有一个解析整数的函数,并且你得到了不符合整数的文本,那么确定下一步该做什么就不是该函数的工作了。需要通知调用者他们提供的字符串格式不正确并且应该做一些事情。

调用者需要处理错误。

您不会中止大多数程序,因为应该包含整数的文件不包含整数。但是您的解析函数确实需要将此事实传达给调用者,而调用者确实需要处理这种可能性。

这就是“捕获异常”的用途。

现在,像 OOM 这样的意外环境条件是另一回事。这通常不是外部代码的错误,但通常也不是编程错误。如果它一个编程错误(即:内存泄漏),那么在大多数情况下它不是你可以处理的。P0709有一整节内容是关于程序能够普遍响应 OOM 的能力(或缺乏能力)。结果是,即使程序针对 OOM 异常进行了防御性编码,它们通常在内存不足时仍然会被破坏。

尤其是在处理那些在您实际使用它们之前不会将页面提交到内存的操作系统时。


推荐阅读