2

考虑这个程序:

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_arrand i_arr,但拒绝s_newand 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_newinew我可以理解这一点,因为两者S[1]都是int[1][1]聚合类型,其元素类型是子聚合(数组的数组S;数组的数组)。但是,C++ 允许省略这些大括号,并且 GCC 接受s_arri_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_arri_arr也是直接初始化的,我认为它们应该以相同的方式解释,并且原始程序应该是格式良好的。

我在这里有什么遗漏,或者这是 GCC 中的错误吗?

我试图通过 GCC Bugzilla 进行搜索,但没有找到任何相关内容。

4

1 回答 1

1

是的,这绝对是一个错误。 new表达式被定义为使用直接初始化规则([expr.new]/18.2),并且大括号省略适用于聚合初始化的所有情况([dcl.init.aggr]/12)。

如果在通过 bugzilla 搜索后找不到错误,请提交错误。

于 2019-09-29T10:35:52.113 回答