initializer_list和GCC 4.9.2 vs GCC trunk

时间:2017-06-26 14:33:32

标签: c++ c++11 gcc

以下是该问题的精简版本:

#include <initializer_list>
#include <iostream>

enum objects { zero, one, two, three, four, five, six, seven };

std::initializer_list<objects> objects_list()
{
    return { zero, one, two, three, four, five, six, seven };
}

int main()
{
    for (auto a : objects_list())
    {
        std::cout << a << ' ';
    }
    std::cout << '\n';
}

我的期望是节目输出:

0 1 2 3 4 5 6 7

这是由GCC 4.9.2确认的,但GCC新鲜的GCC存储库产生:

0 0 -85997960 32712 -1076836160 32765 0 32

似乎基本上是随机数字。

我的程序或GCC有问题吗?

1 个答案:

答案 0 :(得分:5)

N4296§8.5.4/ 5州

  

类型为std::initializer_list<E>的对象是从初始化列表构造的,就像实现一样   分配了Nconst E个元素的临时数组,其中N是元素的数量   初始化列表。使用初始化程序的相应元素对该数组的每个元素进行复制初始化   列表,构造std::initializer_list<E>对象以引用该数组

所以我们被告知std::initializer_list指的是一个临时数组。

和§8.5.4/ 6陈述

  

该数组与任何其他临时对象具有相同的生命周期

该标准提供了此示例,以演示在数组超出范围后访问初始化列表是未定义的行为:

struct A {
std::initializer_list<int> i4;
A() : i4{ 1, 2, 3 } {} // creates an A with a dangling reference
};
  

initializer_list对象在构造函数中初始化    ctor-initializer ,因此数组只会持续存在,直到构造函数退出,因此对i4元素的任何使用都是如此   构造函数退出后产生未定义的行为。 - 例子]

您有一个类似但略有不同的例子涉及复制:

std::initializer_list<objects> objects_list()
{
    return { zero, one, two, three, four, five, six, seven };
}

根据标准中的逻辑,数组{zero, one, two, ...}仅在objects_list函数的持续时间内持续存在。

18.9 / 2 [support.initlist]也支持副本不会持久保存基础数组:

  

复制[std::] initializer list不会复制基础元素。

所以我相信你的代码最终是UB,之前它运作的事实是运气。