这是一道面试题。我告诉他,如果堆栈展开已经在进行中,程序可能会终止。除此之外,如果异常处理得当,您会发现任何问题。我告诉他没有,只要处理得当。但他看起来对我的反应不太满意。
3 回答
好吧,您无法知道是否已经存在活动异常。如果存在,如果您让另一个异常从析构函数中逃脱,程序将终止。
因此,我并没有真正遵循您的论点:
我告诉他没有,只要处理得当。
除了首先不让它从析构函数中逃脱之外,您如何“正确处理”它?如果我是面试官,那将是我的下一个问题。
如果您从析构函数中抛出,这意味着异常实际上正在离开析构函数。所以正确处理的部分是不可能的:你无法知道它将如何处理。
还有一个额外的微妙问题:在许多不平凡的情况下,除非假定析构函数不会抛出,否则不可能(或至少非常昂贵)编写异常安全的代码。如果你的析构函数抛出异常,你的类的用户将不能用它写出好的代码。例如:不可能为容器编写异常安全的析构函数,除非它包含的对象的析构函数保证不会抛出。不会调用terminate()
,但容器析构函数会泄漏资源。
从析构函数中抛出是没有意义的。
析构函数中唯一可恢复的错误是关闭/刷新文件时的 I/O 错误(或网络的类似错误等)。但从这些条件中恢复是微不足道的。只需报告错误并继续。无论如何,您不需要该文件,您只是试图关闭它!因为一个你甚至不需要的文件中的错误而放弃你正在做的任何事情都是浪费的。
析构函数中可能发生的所有其他类型的故障,例如无法解锁互斥锁或释放内存块,可能无法恢复,因此需要调用terminate()
.
另一方面,分配资源的错误,或在计算过程中未能执行某些 I/O,需要抛出,因为计算无法继续。但这不应该发生在析构函数中,或者如果发生,它应该在析构函数中处理(为什么?再一次,让它传播出去是没有意义的,这不会停止错误并且会放弃可能是愉快地继续)。
因此,即使从析构函数中抛出非常安全且定义明确,它也不会给我们带来太多好处。