Consider this program:
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;
}
I think all four variables in the main function should be initialized using aggregate initialization.
However, GCC only accepts s_arr
and i_arr
, but rejects s_new
and i_new
, reporting (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
(note: the last duplicate line is produced by g++)
I also tested on godbolt, none of the gcc versions from 6.1 to 9.2 can compile this program. 6.x and 7.x versions also give the message saying: "sorry, unimplemented: cannot initialize multi-dimensional array with initializer" for i_new
.
Changing {0}
to {{0}}
resolves both s_new
and inew
for all GCC versions tested on godbolt (6.1 to 9.2). I can understand this, as both S[1]
and int[1][1]
are both aggregate types whose element type is a sub-aggregate (array of S
; array of array). However, C++ allows these braces to be elided, and GCC accepts s_arr
and i_arr
, where these braces are elided.
In the other hand, clang 6.0.0 to clang 9.0.0 accepts the original program happily.
In the specification of C++14 (gnu++14 is the default for 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.
The new-initializer should be interpreted as direct-initialization. As s_arr
and i_arr
are also direct-initialized, I think they should be interpreted in the same way, and the original program should be well-formed.
Is there anything that I am missing here, or is this a bug in GCC?
I tried to search through GCC Bugzilla, but didn't find anything relevant.
{0}
is often misleading, as it means "zero-initialize the first element and value-initialize the rest". It's better to just use{}
or()
to value-initialize the entire object (this will set it to 0). Incidentally that also compiles fine on gcc. – rustyx