c ++ 17:永不销毁的临时对象

时间:2019-03-06 01:41:25

标签: c++ gcc language-lawyer c++17 object-lifetime

struct Base {
    Base() {
        std::cout << "Inside:  " << __PRETTY_FUNCTION__ << std::endl;
    }
    ~Base() {
        std::cout << "Inside:  " << __PRETTY_FUNCTION__ << std::endl;
    }
};

struct BaseWrapper {
    const Base &b;
};

int main()
{
    {
        auto *w = new BaseWrapper{{}};
        std::cout << "Inside:  " << __PRETTY_FUNCTION__ << std::endl;
        delete w;
    }
    return 0;
}

当我用C ++ 11或C ++ 14编译时,上面的代码按预期工作,但是当我用C ++ 17编译时,它给了我类似的东西:

Inside:  Base::Base()                                                                                                                                                              
Inside:  int main()

如您所见,从未调用Base ::〜Base()。这对我来说没有多大意义。我已经在Ubuntu 18.04.1 LTS上的GCC 7.3.0和OnlineGDB上测试了此代码。它们都给出相同的结果。

我只是想知道这是C ++ 17中的新功能还是错误?

更新: 我很清楚w->b是一个悬而未决的参考。实际上,我故意编写了这段代码只是为了说明这一点。然后,我在测试时发现了这个问题。

如果要坚持使用GCC 7.3,我真的想知道这个问题有多严重?还是有其他方法可以重现同一问题?或缺陷报告?

2 个答案:

答案 0 :(得分:2)

很显然,创建但未被销毁的临时文件是编译器错误-除非标准说行为未定义。该示例定义良好。标准[class.temporary]中的相关规则:

  

当实现引入具有非平凡构造函数的类的临时对象([class.default.ctor],[class.copy.ctor])时,应确保为该临时对象调用构造函数。同样,析构函数应被调用为具有非平凡析构函数的临时变量([class.dtor])。临时对象被销毁是评估(按词法)包含创建点的完整表达式(intro.execution)的最后一步。 ...

     

在三种情况下,临时变量在与完整表达式结束时不同的位置被销毁。 ...

     

第三个上下文是将引用绑定到临时对象时...

     

此生存期规则的例外是:

     
      
  • ...

  •   
  • 绑定到新初始化器([expr.new])中引用的临时 持续存在,直到包含新初始化器的完整表达式完成

  •   

答案 1 :(得分:0)

看起来像个错误,可能具有参考生存期延长和堆分配的对象。

有一些奇怪的生命周期扩展规则,其中包含引用成员的聚合初始化。

您可以升级编译器,也可以添加一个BaseWrapper(Base const& bin):b(bin){} ctor并观察错误消失。