C++14 中 std::intializer_list 对象的预期生命周期是多少?

Fed*_*dor 8 c++ object-lifetime initializer-list language-lawyer c++14

请考虑这个简化的程序:

#include <iostream>

struct A
{
    A() { std::cout << "A() "; }
    ~A() { std::cout << "~A() "; }
};

int main()
{
    auto l = std::initializer_list<A>{A()};
    std::cout << ". ";
}
Run Code Online (Sandbox Code Playgroud)

https://gcc.godbolt.org/z/1GWvGfxne

GCC在这里打印

A() . ~A()
Run Code Online (Sandbox Code Playgroud)

意思std::initializer_list是在范围结束时被破坏。

叮当印:

A() ~A() . 
Run Code Online (Sandbox Code Playgroud)

std::initializer_list在它建造的那条线上销毁。

两个编译器都在这里正确运行还是其中之一是错误的?

Sto*_*ica 8

这是微妙的。

Astd::initializer_list由底层数组(由编译器生成)支持。这个数组就像一个临时对象,std::initializer_list是一种绑定到它的引用类型。因此,只要“引用”存在,它就会延长临时数组的生命周期。

在 C++14 中,我们不保证复制省略。所以应该发生的事情是好像std::initializer_list<A>{A()}产生了一个临时的initializer_list,将另一个临时数组绑定到它,并将临时数组复制initializer_listl.

std::initializer_list就生命周期延长而言,其行为类似于常规引用。只有原始引用会延长生命周期,而我们的原始引用本身是临时的。因此,在包含 的初始化的完整表达式的末尾,底层数组不存在l。Clang 是正确的。

直接初始化...

std::initializer_list<A> l {A()};
Run Code Online (Sandbox Code Playgroud)

...在两个编译器上产生相同的输出

同时,在为 C++17 编译时,您的原始代码在 GCC 和 Clang 上的行为相同。

  • @Jodocus - [这是一个已知的事实](https://i.imgur.com/3wlxtI0.gifv)。 (3认同)