在clang中返回std :: initializer_list

时间:2015-02-27 21:35:56

标签: c++ c++11 clang clang++

考虑这个代码示例:

#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)时,这段代码工作正常。

2 个答案:

答案 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。