c++17: 一个从未被销毁的临时对象

c++17: A temporary object never destroyed

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?或者是否有任何其他方法可以重现相同的问题?或缺陷报告?

看起来像一个错误,可能与引用生命周期延长和堆分配对象有关。

引用成员的聚合初始化存在奇怪的生命周期延长规则。

您可以升级您的编译器或简单地添加一个 BaseWrapper(Base const& bin):b(bin){} 构造器并观察错误消失。

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

When an implementation introduces a temporary object of a class that has a non-trivial constructor ([class.default.ctor], [class.copy.ctor]), it shall ensure that a constructor is called for the temporary object. Similarly, the destructor shall be called for a temporary with a non-trivial destructor ([class.dtor]). Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created. ...

There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression. ...

The third context is when a reference is bound to a temporary object ...

The exceptions to this lifetime rule are:

  • ...

  • A temporary bound to a reference in a new-initializer ([expr.new]) persists until the completion of the full-expression containing the new-initializer.