GCC 不支持 new 表达式中的大括号省略
GCC does not support brace elision in a new-expression
考虑这个程序:
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
和 i_arr
,但拒绝 s_new
和 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上测试过,none的gcc版本6.1到9.2都可以编译这个程序。 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 New / 17
A new-expression that creates an object of type T initializes that object as follows:
......
(17.2) — Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct initialization.
new-initializer 应该被解释为直接初始化。由于s_arr
和i_arr
也是直接初始化的,我认为它们应该以同样的方式解释,并且原始程序应该是良构的。
这里有什么我遗漏的吗,或者这是 GCC 中的错误?
我试图通过 GCC Bugzilla 进行搜索,但没有找到任何相关内容。
是的,这绝对是一个错误。 new
表达式定义为使用直接初始化规则 ([expr.new]/18.2), and brace elision applies to all cases of aggregate initialization ([dcl.init.aggr]/12)。
如果在 bugzilla 中搜索后找不到错误,请提交错误。
考虑这个程序:
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
和 i_arr
,但拒绝 s_new
和 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上测试过,none的gcc版本6.1到9.2都可以编译这个程序。 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 New / 17
A new-expression that creates an object of type T initializes that object as follows:
......
(17.2) — Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct initialization.
new-initializer 应该被解释为直接初始化。由于s_arr
和i_arr
也是直接初始化的,我认为它们应该以同样的方式解释,并且原始程序应该是良构的。
这里有什么我遗漏的吗,或者这是 GCC 中的错误?
我试图通过 GCC Bugzilla 进行搜索,但没有找到任何相关内容。
是的,这绝对是一个错误。 new
表达式定义为使用直接初始化规则 ([expr.new]/18.2), and brace elision applies to all cases of aggregate initialization ([dcl.init.aggr]/12)。
如果在 bugzilla 中搜索后找不到错误,请提交错误。