c ++ 17:一个永远不会被破坏的临时对象

问题描述 投票:3回答:2
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中的新功能还是一个bug?

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

我真正想知道的是这个问题有多严重,以防万一我必须坚持使用GCC 7.3?或者是否有其他方法可以重现相同的问题?还是缺陷报告?

c++ gcc language-lawyer c++17 object-lifetime
2个回答
2
投票

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

当实现引入具有非平凡构造函数的类的临时对象([class.default.ctor],[class.copy.ctor])时,它应确保为临时对象调用构造函数。类似地,析构函数应该用一个非平凡的析构函数([class.dtor])来调用。临时对象作为评估全表达式([intro.execution])的最后一步被销毁,该表达式(词法上)包含创建它们的点。 ...

有三种情况,临时表在与完整表达结束时不同的地方被摧毁。 ...

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

此生命周期规则的例外情况是:

  • ...
  • 在new-initializer([expr.new])中对引用的临时绑定将持续到包含new-initializer的full-expression完成为止。

0
投票

看起来像一个bug,可能带有引用生命周期扩展和堆分配对象。

使用引用成员的聚合初始化有奇怪的生命周期扩展规则。

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

© www.soinside.com 2019 - 2024. All rights reserved.