为什么不能从析构函数抛出异常,但可以从复制构造函数抛出异常



似乎在析构函数抛出多个异常的情况下,你不能从析构函数抛出异常。

在Effective c++中,Scott Meyers使用了一个vector示例,其中第一个元素在析构期间抛出异常,然后第二个元素抛出,这对c++造成了问题(c++不能处理多个异常)。

当然这种情况(向量操纵元素和元素抛出异常)也可能发生在复制构造函数实现深度复制期间?

编辑:

我们是在说,调用底层函数的递归性质与复制构造函数不同吗?

异常不应该从析构函数中抛出,因为当抛出异常时,编译器将清除作用域中的变量,从而调用它们的析构函数。如果这些也抛出异常,您将处于糟糕的状态。

构造函数和析构函数的不同之处在于

  • 首先,对象的销毁与unwind绑定在一起,而unwind在抛出异常时发生。展开与对象的构造无关。也就是说,析构函数和异常之间已经存在一种关系。

  • 当某些代码在对象的构造过程中被中断时,可以安全地处理。可以回滚资源,就好像从未请求过对象的创建一样。此外,后续代码不运行也没关系,比如其他对象的构造。在销毁的情况下,必须正确执行,否则资源会泄漏。放弃析构函数是不对的,因为这是清理对象的最后机会。此外,如果析构函数是多个调用链的一部分,则永远不调用其余析构函数是不行的。忽略执行析构函数会导致程序出现一些永久性的问题。

假设你有这样的情况:

{
  A a;
  B b;
  C c;
  // ...
}

假设块中的语句抛出,则A、B和C的析构函数按相反的顺序执行:C::~C~B::BA::~A。假设C::~C抛出。这意味着不仅c的破坏是不完整的,而且BA的破坏也不会发生。该语句块的清理代码将被丢弃。

语义应该是什么?

如果在这种情况下没有析构函数可以被放弃,这意味着C::~C必须在抛出时重新执行。但这可能会触发一个无限循环。

或者,unwind仍然可以执行ba的剩余析构函数。但这仍然意味着C的析构函数被抛弃了,C没有被正确地销毁。

最新更新