C++14 中 std::intializer_list 对象的预期寿命是多少?
What is expected lifetime of std::intializer_list object in C++14?
请考虑这个简化的 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 << ". ";
}
https://gcc.godbolt.org/z/1GWvGfxne
GCC 在此处打印
A() . ~A()
意味着 std::initializer_list
在作用域结束时被破坏。
Clang 打印:
A() ~A() .
在建造的那一行摧毁std::initializer_list
。
两个编译器的行为是否正确,或者其中一个是错误的?
很微妙。
A std::initializer_list
由底层数组(由编译器生成)支持。这个数组就像一个临时对象,std::initializer_list
是一种绑定到它的引用类型。因此只要“引用”存在,它就会延长临时数组的生命周期。
在 C++14 中,我们不保证复制省略。所以应该发生的事情就好像std::initializer_list<A>{A()}
产生了一个临时initializer_list
,将另一个临时数组绑定到它,并复制临时 initializer_list
到 l
.
就生命周期延长而言,std::initializer_list
的行为类似于常规引用。只有原始引用可以延长生命周期,而我们的原始引用本身就是暂时的。因此,在包含 l
的初始化的完整表达式结束时,底层数组不存在。 Clang 是正确的。
直接初始化...
std::initializer_list<A> l {A()};
... 在两个编译器上生成 same output。
同时,当 compiling for C++17 时,您的原始代码在 GCC 和 Clang 上的行为相同。
根据cppreference:
Until the resolution of CWG issue 1696, a temporary is permitted to
bound to a reference member in a constructor initializer list, and it
persists only until the constructor exits, not as long as the object
exists. Such initialization is ill-formed since CWG 1696, although
many compilers still support it (a notable exception is clang).
请考虑这个简化的 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 << ". ";
}
https://gcc.godbolt.org/z/1GWvGfxne
GCC 在此处打印
A() . ~A()
意味着 std::initializer_list
在作用域结束时被破坏。
Clang 打印:
A() ~A() .
在建造的那一行摧毁std::initializer_list
。
两个编译器的行为是否正确,或者其中一个是错误的?
很微妙。
A std::initializer_list
由底层数组(由编译器生成)支持。这个数组就像一个临时对象,std::initializer_list
是一种绑定到它的引用类型。因此只要“引用”存在,它就会延长临时数组的生命周期。
在 C++14 中,我们不保证复制省略。所以应该发生的事情就好像std::initializer_list<A>{A()}
产生了一个临时initializer_list
,将另一个临时数组绑定到它,并复制临时 initializer_list
到 l
.
std::initializer_list
的行为类似于常规引用。只有原始引用可以延长生命周期,而我们的原始引用本身就是暂时的。因此,在包含 l
的初始化的完整表达式结束时,底层数组不存在。 Clang 是正确的。
直接初始化...
std::initializer_list<A> l {A()};
... 在两个编译器上生成 same output。
同时,当 compiling for C++17 时,您的原始代码在 GCC 和 Clang 上的行为相同。
根据cppreference:
Until the resolution of CWG issue 1696, a temporary is permitted to bound to a reference member in a constructor initializer list, and it persists only until the constructor exits, not as long as the object exists. Such initialization is ill-formed since CWG 1696, although many compilers still support it (a notable exception is clang).