【问题标题】:Why cannot throw exceptions from destructors but can from copy constructor? [duplicate]为什么不能从析构函数抛出异常,但可以从复制构造函数抛出异常? [复制]
【发布时间】:2014-08-12 07:19:53
【问题描述】:

如果从析构函数中抛出多个异常,您似乎不能从析构函数中抛出异常。

在 Effective C++ 中,Scott Meyers 使用向量示例,其中第一个元素在销毁期间抛出异常,然后第二个元素抛出 - 导致 C++ 出现问题(不能处理多个异常)。

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

编辑:

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

【问题讨论】:

  • 可以从析构函数中抛出。有时它只会导致非常讨厌的行为(abort)。你可以抛出一个拷贝构造函数是很重要的;这些通常还需要获取资源,而这可能会失败。
  • 抛出异常会展开堆栈。展开堆栈在堆栈上的对象上运行 dtors。 C++ 说如果 unwind 得到一个异常,那么 C++ 运行时调用 terminate()。默认情况下,terminate() 调用 abort()。
  • 您的问题是什么?是“你为什么不应该从析构函数中抛出?”还是“为什么可以从复制构造函数中抛出?”?
  • @DDrmmr 是的-为什么可以从复制委托人那里抛出?在这方面与 dtor 不同的复制构造函数是什么? (所以它有点 Q)。
  • “这种情况(向量操作元素和元素抛出异常)肯定也可能发生在复制构造函数实现深度复制期间吗?” - 试着想出一个发生这种情况的例子!

标签: c++ destructor copy-constructor


【解决方案1】:

异常不应该从析构函数中抛出,因为当你抛出异常时,编译器会清理范围内的变量,从而调用它们的析构函数。如果这些也抛出异常,你的状态就会很糟糕。

【讨论】:

  • 您的意思是“编译器”进行清理吗?它肯定在运行时吗?那么你是说析构函数的问题是析构函数的递归性质可能调用其他析构函数吗?我不确定我是否理解为什么它会从复制构造函数中抛出异常?
  • 编译器会像离开任何作用域一样进行清理:删除作用域中的所有变量(并调用它们的 dtors)。当你释放堆栈上的变量时,你不会调用复制构造函数。
  • 编译器生成代码进行清理和/或只是假设使用的变量空间再次空闲(因此它可以再次用于其他代码部分变量)...
  • @user997112 问题是一次只能激活一个异常。如果抛出异常,堆栈被解开,导致对象的析构函数抛出异常,那么第一个异常呢?现在有两个同时活跃,这是不允许的。 (这是一种简化——只要捕获到异常,就可以在析构函数中抛出异常)。
  • 考虑到在 C++17 中添加了 std::uncaught_exceptions 有点过时的建议,它可用于检测堆栈是否由于抛出不同的异常而展开,从而防止双重抛出,这将取消程序;有时抛出而不是其他时候抛出的语义是否正确,这取决于您的设计,但能力就在那里
【解决方案2】:

构造函数和析构函数(关于抛出)的区别在于

  • 首先,对象的销毁与展开相关联,当抛出异常时会发生展开。展开与对象的构造无关。也就是说,析构函数和异常已经有了关系。

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

假设你有这样的情况:

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

假设块中的语句抛出,那么 A、B 和 C 的析构函数以相反的顺序执行:C::~C 然后~B::BA::~A。假设C::~C 抛出。这意味着不仅c 的销毁不完整,而且BA 的销毁也不会发生。这个语句块的清理代码被简单地放弃了。

语义应该是什么?

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

或者,展开仍然可以为ba 执行剩余的析构函数。但这仍然意味着 C 析构函数已被废弃,C 未正确销毁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-04
    • 1970-01-01
    • 2019-07-11
    • 1970-01-01
    • 1970-01-01
    • 2013-04-03
    • 2012-10-28
    • 2015-08-26
    相关资源
    最近更新 更多