考虑这个程序:
struct S {
int m;
};
int main() {
S s_arr[1]{0};
S *s_new = new S[1]{0};
int i_arr[1][1]{0};
int (*i_new)[1] = new int[1][1]{0};
return 0;
}
我认为主函数中的所有四个变量都应该使用聚合初始化来初始化。
但是,GCC 只接受s_arr
and i_arr
,但拒绝s_new
and i_new
,报告(g++ 8.3.0 on Ubuntu):
test.cpp: In function ‘int main()’:
test.cpp:7:26: error: could not convert ‘0’ from ‘int’ to ‘S’
S *s_new = new S[1]{0};
^
test.cpp:9:38: error: array must be initialized with a brace-enclosed initializer
int (*i_new)[1] = new int[1][1]{0};
^
test.cpp:9:38: error: array must be initialized with a brace-enclosed initializer
(注意:最后一个重复行是由 g++ 产生的)
我也在godbolt上测试过,从 6.1 到 9.2 的 gcc 版本都不能编译这个程序。6.x 和 7.x 版本还给出消息说:“抱歉,未实现:无法使用初始化程序初始化多维数组” i_new
。
更改{0}
为{{0}}
解决了在 Godbolt 上测试的所有 GCC 版本(6.1 到 9.2)s_new
。inew
我可以理解这一点,因为两者S[1]
都是int[1][1]
聚合类型,其元素类型是子聚合(数组的数组S
;数组的数组)。但是,C++ 允许省略这些大括号,并且 GCC 接受s_arr
和i_arr
,其中这些大括号被省略。
另一方面,clang 6.0.0 到 clang 9.0.0 欣然接受原程序。
在 C++14 的规范中(gnu++14 是 GCC 6.5/7.4/8.3/9.2 的默认值),
5.3.4 新 / 17
创建 T 类型对象的 new 表达式按如下方式初始化该对象:
……
(17.2) — 否则,根据 8.5 的初始化规则解释 new-initializer 以进行直接初始化。
new-initializer 应该被解释为直接初始化。由于s_arr
和i_arr
也是直接初始化的,我认为它们应该以相同的方式解释,并且原始程序应该是格式良好的。
我在这里有什么遗漏,或者这是 GCC 中的错误吗?
我试图通过 GCC Bugzilla 进行搜索,但没有找到任何相关内容。