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?或者是否有其他方法可以重现相同的问题?还是缺陷报告?
显然,创建但未被销毁的临时文件是编译器错误 - 除非标准说明行为未定义。然而,这个例子很明确。标准[class.temporary]的相关规则:
当实现引入具有非平凡构造函数的类的临时对象([class.default.ctor],[class.copy.ctor])时,它应确保为临时对象调用构造函数。类似地,析构函数应该用一个非平凡的析构函数([class.dtor])来调用。临时对象作为评估全表达式([intro.execution])的最后一步被销毁,该表达式(词法上)包含创建它们的点。 ...
有三种情况,临时表在与完整表达结束时不同的地方被摧毁。 ...
第三个上下文是引用绑定到临时对象时...
此生命周期规则的例外情况是:
- ...
- 在new-initializer([expr.new])中对引用的临时绑定将持续到包含new-initializer的full-expression完成为止。
看起来像一个bug,可能带有引用生命周期扩展和堆分配对象。
使用引用成员的聚合初始化有奇怪的生命周期扩展规则。
您可以升级编译器或只是添加一个BaseWrapper(Base const& bin):b(bin){}
ctor并观察错误消失。