Direct-init vs. list-init in array new-expression
Asked Answered
M

1

8

Basically, why is this valid:

auto p1 = new int[10]{5};

but this is not:

auto p1 = new int[10](5);

And more generally what are the rules for the new-expression initializer?

I found the following:

— If the new-initializer is omitted, the object is default-initialized (8.5). [ Note: If no initialization is performed, the object has an indeterminate value. — end note ] — Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct- initialization.

So is the second case invalid because smth like T((5)) is invalid (direct initialization from expression (5))? Or what is the reason?

EDIT: well, my suggestion of (()) thing seems dumb because I see no reason why that should only apply to array new-expression.

Madaras answered 5/4, 2018 at 3:24 Comment(0)
C
7

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);.

Combinative answered 5/4, 2018 at 3:40 Comment(1)
The shortness of this answer reflects very well the conciseness of the few tens of specification pages that describe the initialization recursive process!Salary

© 2022 - 2024 — McMap. All rights reserved.