考虑这个代码示例:
#include <initializer_list>
#include <iostream>
int main()
{
for(auto e: []()->std::initializer_list<int>{return{1,2,3};}())
std::cout<<e<<std::endl;
return 0;
}
我尝试用g ++编译它(gcc版本4.9.2(Debian 4.9.2-10)) 并且输出是正确的。 在clang ++中(Debian clang版本3.5.0-9(标签/ RELEASE_350 / final)(基于LLVM 3.5.0))输出例如:
0
2125673120
32546
第一行总是0,最后两行是&#34; random&#34; 。
clang或其他什么错误?我认为这个代码示例是正确的。
更新
当lambda函数返回类型是其他东西(例如std :: vector或std :: array)时,这段代码工作正常。
答案 0 :(得分:4)
从C ++ 11 8.5.4列表初始化[dcl.init.list]:
5类型
std::initializer_list<E>
的对象是从初始化列表构造的,就好像实现分配了N
类型为E
的元素数组,其中N
是数字初始化列表中的元素。使用初始化列表的相应元素对该数组的每个元素进行复制初始化,并构造std::initializer_list<E>
对象以引用该数组。如果需要缩小转换来初始化任何元素,则程序格式不正确。6数组的生命周期与
initializer_list
对象的生命周期相同。
lambda的return
语句初始化临时std::initializer_list<int>
并返回其副本。这一切都很好,除了它引用的数组的生命周期在完整表达式结束时结束。通过lambda外部的initializer_list
访问死数组会导致未定义的行为。
initializer_list
不是容器,它是对临时容器的引用。如果你试图像容器一样使用它,那么你将会遇到糟糕的时间。
在C ++ 14(引用N4140)中,第6段被澄清为:
6该数组与任何其他临时对象(12.2)具有相同的生命周期,除了从数组初始化
initializer_list
对象延长了数组的生命周期,就像将引用绑定到临时对象一样。
以CWG issue 1290的决议。这种澄清使得不可能使用initializer_list
作为例如C ++ 11意图的成员变量。但是,即使在C ++ 14中,您的程序也有未定义的行为。
答案 1 :(得分:1)
在C ++ 11中,在原始初始化列表对象的生命周期结束后,不保证底层数组存在。因此,您的代码可能会出现未定义的行为。切换到C ++ 14。