【问题标题】:Why would a new[] expression ever invoke a destructor?为什么 new[] 表达式会调用析构函数?
【发布时间】:2019-03-22 20:32:37
【问题描述】:

来自 C++17 标准(草案here),[expr.new]:

如果 new-expression 创建了一个对象或类类型的对象数组,则对分配函数、解除分配函数和构造函数进行访问和歧义控制。 如果 new-expression 创建了一个类类型的对象数组,则可能会调用析构函数。

为什么new[] 会调用析构函数?毕竟它是新的。它不是删除。

【问题讨论】:

    标签: c++ c++17 new-operator


    【解决方案1】:

    如果缓冲区中任何对象的构造引发异常,则必须销毁先前构造的对象。这需要一个可用的析构函数。

    【讨论】:

    • 澄清:这是否意味着一个新的(非数组)也可能调用析构函数?从我所看到的情况来看,我相信是这样,但我想确保自己这是真的。
    • @DanielRobertMiller - 未完全构造的对象不会调用其析构函数。非数组 new 不需要可用的 d'tor。
    【解决方案2】:

    您在引用标准时没有考虑过“潜在地”这个词。
    这意味着有可能调用析构函数可能发生。如果数组中的任何对象的构造引发异常,就会发生

    结合[class.dtor]/12.4 中提到[expr.new]的以下引用,这一点变得清晰。

    在每种情况下,调用的上下文都是对象构造的上下文。析构函数也通过使用删除表达式来隐式调用,用于由 new 表达式分配的构造对象;调用的上下文是删除表达式。 [ 注意:类类型的数组包含多个子对象,每个子对象都调用析构函数。  — 尾注 ] 也可以显式调用析构函数。 如果调用或在[expr.new][class.base.init][except.throw] 中指定,则可能调用析构函数。如果一个可能被调用的析构函数被删除或无法从调用上下文中访问,则该程序是格式错误的。

    【讨论】:

      【解决方案3】:

      在行动:

      #include <iostream>
      
      int counter;
      
      class Destruct
      {
      public:
          Destruct()
          {
              if (counter++ > 5)
                  throw counter;
          }
      
          ~Destruct()
          {
              std::cout << "Dtor called\n";
          }
      };
      
      int main()
      {
          try
          {
              new Destruct[10];
          }
          catch (...){}
      }
      

      你会看到类似这样的输出:

      Dtor called
      Dtor called
      Dtor called
      Dtor called
      Dtor called
      Dtor called
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-04
        • 2014-03-05
        • 2018-05-24
        • 2015-08-21
        • 1970-01-01
        • 2021-04-01
        • 1970-01-01
        相关资源
        最近更新 更多