为什么我可以从{}初始化一个常规数组,但不能从std::数组初始化?

Why can I initialize a regular array from {}, but not a std::array

本文关键字:数组 初始化 常规 std 一个 但不能 我可以 为什么      更新时间:2023-10-16

这行得通:

int arr[10] = {};

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

为什么不工作:

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

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

警告:成员' std::array<int,>::_M_elems '缺少初始化式

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

虽然可能不明显,聚合初始化发生在临时对象上,然后将其用作复制构造函数的参数。更习惯的初始化方式如下:

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

尽管这仍然留下警告。

警告包含在gcc bug report: - - wmissing -field-initializers放松请求中,其中一条注释说:

[…当然,MyType x = {};应该得到支持,如下所示:

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一起工作。

我们可以在Clang开发者列表的头部看到这个主题:- wmissing -field-initializer

参考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++,虽然注意到使用{}是无效的C99。有人可能会说这只是一个警告,但这似乎是使用{}进行聚合初始化的惯用c++,如果我们使用-Werror将警告转换为错误,则会出现问题。

首先,您可以({})初始化器与std::array对象一起使用,但在语义上,它代表使用临时值初始化的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版本时,为什么决定使用({})而不是= {} ?

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

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

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

我的理解是std::array实际上是一个类,它的唯一成员是C数组。所以双花括号是有意义的:外面的花括号表示你正在初始化类,然后里面的花括号默认初始化类中唯一的成员。

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