删除从析构函数

时间:2018-03-15 01:39:16

标签: c++ c++11 c++17

我理解C ++中的当前规则说:

  

如果由于异常而在已经堆栈展开的情况下抛出析构函数,则调用std::terminate

在探究规则原因的原因时,我遇到了以下代码中描述的情况。

  1. X的析构函数抛出。

  2. Y在自己的析构函数中删除X

  3. 因此Y的析构函数会抛出。

  4. 我不清楚Y抛出(3.)的事实是否应该通过标准规则触发std::terminate。我希望它不应该,并按照我的希望对gcc进行测试。

    熟悉标准法律术语的人能澄清一下吗?应该(3.)触发std::terminate吗?

    #include <iostream>
    
    struct X {
      ~X() noexcept(false) {
        std::cout << "Destroying X\n";
        throw std::runtime_error("Exception");
      }
    };
    
    struct Y {
       X * x_;
    
      explicit Y(X * x) : x_{x} { }
    
      ~Y() noexcept(false) {
        std::cout << "Destroying Y\n";
        delete x_;
      }
    };
    
    int main() {
      try {
        Y y(new X());
        std::cout << "Living\n";
      }
      catch (const std::exception & e) {
        std::cout << "Caught " << e.what() << '\n';
      }
    }
    

    使用g ++版本5.4.0-6ubuntu1~16.04.9和--std=c++17我得到:

    Living
    Destroying Y
    Destroying X
    Caught Exception
    

1 个答案:

答案 0 :(得分:3)

标准在[except.terminate]p1.4中说明:

  
      
  • 在堆栈展开期间通过抛出异常终止对象的销毁,或
  •   

2)因为Y超出范围而发生。 1)抛出异常,开始堆栈展开。在堆栈展开期间,更具体地说是在销毁std::terminate时 - 这是2)。它抛出异常,因此满足该点并调用Y

正是您正在执行的操作,除了重要的一点:在堆栈展开期间 。当一个作用域结束时,不会发生堆栈展开,它只会在抛出异常并且超出它抛出的当前作用域时发生。

throw 1;因异常而未被销毁。添加std::terminate即可查看对{{1}}的投放。

因此,该条款不适用,您的代码确实有效。