The 1st one is valid because of list initialization (since C++11),
new T { arg1, arg2, ... }
and
If T is an aggregate type, aggregate initialization is performed.
int[10]
is an array type which belongs to aggregate type, then aggregate initialization is performed,
If the number of initializer clauses is less than the number of members and bases (since C++17)
or initializer list is completely empty, the remaining members and bases (since C++17)
are initialized by their default initializers, if provided in the class definition, and otherwise (since C++14)
by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
So auto p1 = new int[10]{5};
will create a pointer to array, whose first element is initialized as 5
, the remaining elements are initialized as 0
.
The 2nd one is direct initialization, so new int[10](5);
means initialize the array int[10]
from a single int
5
directly; which is invalid.
In fact, for the array new expression you can't specify a non-empty parenthesized initializer.
If type is an array type, an array of objects is initialized.
- If initializer is absent, each element is default-initialized
- If initializer is an empty pair of parentheses, each element is value-initialized.
- If initializer is a brace-enclosed list of arguments, the array is aggregate-initialized. (since C++11)
So
auto p1 = new int[10]; // valid
auto p2 = new int[10](); // valid
auto p3 = new int[10]{5}; // valid
auto p4 = new int[10](5); // invalid
EDIT
From the point view of the standard, as you quoted, [expr.new]/18:
A new-expression that creates an object of type T initializes that
object as follows:
- If the new-initializer is omitted, the object is default-initialized ([dcl.init]). [ Note: If no initialization is performed, the object
has an indeterminate value. — end note ]
=> Applies for auto p1 = new int[10];
, leads to default-initialization.
- Otherwise, the new-initializer is interpreted according to the initialization rules of [dcl.init] for direct-initialization.
And [dcl.init]/17:
- (17.1) If the initializer is a (non-parenthesized) braced-init-list or is = braced-init-list, the object or reference is list-initialized.
=> Applies for auto p3 = new int[10]{5};
, leads to list initialization, details are explained above.
- (17.4) If the initializer is (), the object is value-initialized.
=> Applies for auto p2 = new int[10]();
, leads to value initialization.
- (17.5) Otherwise, if the destination type is an array, the program is ill-formed.
=> Applies for auto p4 = new int[10](5);
.