为什么我可以从{}初始化常规数组,而不是std :: array

时间:2015-07-07 14:48:10

标签: c++ c++11 compiler-warnings g++4.8 aggregate-initialization

这有效:

int arr[10] = {};

arr的所有元素都被初始化为零。

为什么这不起作用:

std::array<int, 10> arr({}); 

我从g ++(版本4.8.2)收到以下警告:

  

警告:缺少成员'std :: array&lt; int,10ul&gt; :: _ M_elems'

的初始值设定项

3 个答案:

答案 0 :(得分:12)

有两个问题,一个是风格和警告问题。

虽然可能不是很明显,但是聚合初始化发生在临时,然后被用作复制构造函数的参数。这种初始化的惯用程度如下:

std::array<int, 10> arr = {}; 

虽然这仍然留下警告。

警告由gcc bug report: - -Wmissing-field-initializers relaxation request 涵盖,其中一条评论说:

  

[...]当然,说MyType x = {}的C ++语法;应该得到支持,   如下所示:

     

http://en.cppreference.com/w/cpp/language/aggregate_initialization

     

例如:

struct S {
  int a;
  float b;
  std::string str;
};

S s = {}; // identical to S s = {0, 0.0, std::string};
     

由于前面评论中所述的原因,不应该发出警告。

后续评论说:

  

我关于零初始化的陈述是不准确的(谢谢),但是   一般的观点仍然存在:在C中你必须写&#39; = {0}&#39;以来   语言不支持empty-braces初始化程序(你得到一个   警告与-pedantic);在C ++中,你可以写&#39; = {}&#39;或者&#39; T foo =   T();&#39;,但你不需要写&#39; = {0}&#39;具体

最新版本的gcc不会针对此案例see it live working with gcc 5.1生成此警告。

我们可以在thead中的Clang开发人员列表中看到此主题:-Wmissing-field-initializers

作为参考,草案C ++ 11标准部分8.5.1 [dcl.init.aggr] 表示:

  

如果列表中的初始化子句数少于   聚合中的成员,然后每个成员未明确初始化   应从空的初始化列表(8.5.4)初始化。 [   例如:

struct S { int a; const char* b; int c; };
S ss = { 1, "asdf" };
     

使用1,ss.b和#34; asdf&#34;和ss.c初始化ss.a,其值为   形式为int()的表达式,即0.-end example]

因为这是有效的C ++,尽管使用{}指出的是无效的C99。有人可能会说它只是一个警告,但这似乎是使用{}进行聚合初始化的惯用C ++,如果我们使用-Werror将警告转换为错误,则会出现问题。

答案 1 :(得分:5)

首先,可以使用({})初始值设定项和std::array对象,但语义上代表使用临时值初始化{的复制构造函数进行直接初始化{1}}对象,即它相当于

std::array

它实际上应该编译。

其次,当你可以做的时候,你真的不必走std::array<int, 10> arr(std::array<int, 10>{}); 方式

({})

std::array<int, 10> arr = {};

两者中的第一个在语法上与std::array<int, 10> arr{}; 最相似,这让我想知道你为什么一开始就没有尝试过。在构建int arr[10] = {};语法的({})版本时,为什么决定使用= {}而不是std::array

答案 2 :(得分:2)

当用-Werror进行编译时,足够的人已经指出这是一个“问题”,我认为值得一提的是,如果你加倍,问题就会消失:

std::array<int, 10> arr{{}};

在gcc 4.9.2上没有对我发出任何警告。

为了解释它的原因添加一点:我的理解是std :: array实际上是一个以C数组作为唯一成员的类。所以在括号上加倍是有道理的:外括号表示你正在初始化类,然后内括号默认初始化该类的唯一成员。

因为当一个类中只有一个变量时不存在歧义,所以只使用一对{}应该是合理的,但gcc在这里过于迂腐,并发出警告。