11

这有效:

int arr[10] = {};

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

为什么这不起作用:

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

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

警告:成员 'std::array<int, 10ul>::_M_elems'</p> 缺少初始化程序

4

3 回答 3

12

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

尽管可能并不明显,聚合初始化发生在一个临时对象上,然后用作复制构造函数的参数。更惯用的初始化方法如下:

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

虽然这仍然留下警告。

该警告包含在gcc 错误报告中:--Wmissing-field-initializers 放宽请求,其中一条评论说:

[...]当然,说 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 中,您必须编写 '= {0}' 因为该语言不支持空括号初始化程序(您会收到 -pedantic 警告); 在 C++ 中,你可以写 '= {}' 或 'T foo = T();',但你不需要专门写 '= {0}'。

对于这种情况,最新版本的 gcc 不会产生此警告,请查看它与 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" };

将 ss.a 初始化为 1,将 ss.b 初始化为“asdf”,将 ss.c 初始化为 int() 形式的表达式的值,即 0。 —end example ]

因此这是有效的 C++,尽管如前所述 using{}不是有效的 C99。有人可能会争辩说这只是一个警告,但这似乎是 C++{}用于聚合初始化的惯用方式,如果我们-Werror将警告转化为错误,则会出现问题。

于 2015-07-07T14:51:35.860 回答
5

首先,您可以({})初始化程序与std::array对象一起使用,但在语义上代表使用来自临时值初始化std::array对象的复制构造函数进行直接初始化,即它相当于

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

它实际上应该编译。

其次,当你能做到的时候,你真的不必走这({})条路

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

或者

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

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

于 2015-07-07T19:13:37.363 回答
4

有足够多的人在编译时指出这是一个“问题” -Werror,我认为值得一提的是,如果你只是加倍,问题就会消失:

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

在 gcc 4.9.2 上不会对我产生任何警告。

补充一点为什么会解决它:我的理解是 std::array 实际上是一个以 C 数组作为其唯一成员的类。所以加倍大括号是有意义的:外大括号表示您正在初始化类,然后内大括号默认初始化类的唯一成员。

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

于 2015-07-09T02:25:33.107 回答