Aggregate initialization - cppreference.com

Initializes an aggregate from an initializer list. It is a form of

list-initialization

.(since C++11)

Syntax

T object= {arg1, arg2, ...};(1) T object{arg1, arg2, ...};(2) (since C++11)T object= { .designator1=arg1, .designator2{arg2}...};(3) (since C++20)T object{ .designator1=arg1, .designator2{arg2}...};(4) (since C++20)T object= {arg1, arg2, ..., .designator1=arg1, .designator2{arg2}...};(5) (since C++29)T object{arg1, arg2, ..., .designator1=arg1, .designator2{arg2}...};(6) (since C++29)1,2) Initializing an aggregate with an ordinary initializer list. No designator is allowed.

3,4) Initializing an aggregate with designated initializers (aggregate class only).

5,6) Initializing an aggregate with an ordinary initializer list (which must only initialize base classes) and then designated initializers.

Explanation

Aggregate initialization initializes each

element

of an aggregate with the corresponding initializer in the initializer list, in the element order. An aggregate is either an array or a class that meets certain criteria, see

below

.

The effects of aggregate initialization are:

Each

initializer clause

(that does not have a designator)(since C++20)

copy-initializes

an aggregate element in order of array subscript/appearance in the class definition.

If the initializer clause is an expression:

Implicit conversions are allowed as per copy-initialization, except that narrowing conversions are prohibited(since C++11).

If an

implicit conversion sequence

cannot be formed that converts the expression to the type of the corresponding aggregate element e, and e is itself an aggregate with at least one element, brace elision is assumed. In this case, subsequent initializer clauses appertain to the elements of e. See

below

for details. The aggregate element e is copy-initialized from a brace-enclosed initializer list consisting of the initializer clauses that appertain to its subaggregate elements (or, recursively, to aggregate elements of these elements), in appearance order.

If the initializer clause is a nested initializer list (not an expression), the corresponding aggregate element is copy-list-initialized from that clause.

structA{intx;structB{inti;intj;}b;}a={1,{2,3}};// initializes a.x with 1, a.b.i with 2, a.b.j with 3Each initializer with a designator initializes the member associated with the member named by the designator.

The identifier in each designator must name a direct non-static data member of the aggregate T, and all designators in the designated initializer list must appear in the same order as the data members of T.

(until C++29)The identifier in each designator must name a direct non-static data member of either the aggregate T or an unambiguous base class of T, where every interleaving base class is an aggregate. All designators in the designated initializer list must appear in non-decreasing element order.

(since C++29)If the identifier names a member of an anonymous union, the union is initialized with “{D}”, where D is the designated initializer clause.

Otherwise, if the identifier names a direct non-static data member of T, the named member is initialized from the brace-or-equal initializer that follows the designator. Narrowing conversions are prohibited.

Otherwise, the identifier names a (direct or indirect) member of a direct base class B. The base class subobject of type B must not have been initialized from an ordinary initializer list, and it is copy-initialized from a brace-enclosed designated initializer list consisting of the designated initializer clauses that name members of B.

(since C++29)structA{intx;inty;intz;};Aa{.y=2,.x=1};// error; designator order does not match declaration orderAb{.x=1,.z=2};// ok, b.y initialized to 0structC{union{inta;constchar*p;};intx;}c={.a=1,.x=3};// initializes c.a with 1 and c.x with 3// C++29 designated initializers for base class members:structA{inta;};structB:A{intb;};structC:B{intc;};// the A element is initialized from {.a=1}Bx=B{.a=1};// the B element is initialized from {.a=2, .b=3}// which leads to its A element being initialized from {.a=2}Cy=C{.a=2,.b=3,.c=4};(since C++20)For a non-union aggregate, each aggregate element that is not explicitly initialized is initialized as follows:

If the element has a default member initializer, the element is initialized from that initializer.

(since C++14)Otherwise, the element must not be a reference. The element is

copy-initialized

from an empty initializer list.

For a union aggregate, if the initializer list is empty:

If any member has a default member initializer, the element is initialized from that initializer.

(since C++14)Otherwise, the first member of the union (if any) is

copy-initialized

from an empty initializer list.

In any case, the initializations of the elements of the aggregate are evaluated in the element order. That is, all value computations and side effects associated with a given element are sequenced before those of any element that follows it in order.

structS{inta;constchar*b;intc;intd=b[a];};Sss={1,"asdf"};// Initializes ss.a with 1// then initializes ss.b with "asdf"// then initializes ss.c with int{} (that is, 0)// then initializes ss.d with ss.b[ss.a] (that is, 's')If the object is an array of unknown size, the size of the array is the number of explicitly initialized elements (which must not be zero). Note that the object in this case cannot be a non-static data member: a member must have complete type.

intx[]={1,3,5};// x has 3 elementsstructY{inti,j,k;};Ya[]={1,2,3,4,5,6};Xb[2]={{1,2,3},{4,5,6}};// a and b have the same type and valueintz[]={};// Error: cannot declare an array without any elementstructS{inty[]={0};};// error: non-static data member of incomplete typeIf the object is a union, there must be at most one explicitly initialized element.

unionu{inta;constchar*b;};ua={1};// OK: explicitly initializes member `a`ub={0,"asdf"};// error: explicitly initializes two membersuc={"asdf"};// error: int cannot be initialized by "asdf"// C++20 designated initializer listsud={.b="asdf"};// OK: can explicitly initialize a non-initial memberue={.a=1,.b="asdf"};// error: explicitly initializes two membersDefinitions

Aggregate

An aggregate is one of the following types:

array types

class types that has

no user-declared constructors

(until C++11)no

user-provided

,

inherited

, or

explicit

constructors

(since C++11)
(until C++20)no user-declared or inherited constructors

(since C++20)no private or protected direct non-static data members

no virtual member functions

Element

The elements of an aggregate are:

for an array, the array elements in increasing subscript order, or

for a class, the non-static data members that are not anonymous

bit-fields

, in declaration order.

(until C++17)for a class, the direct base classes in declaration order, followed by the direct non-static data members that are neither anonymous

bit-fields

nor members of an

anonymous union

, in declaration order.

(since C++17)Appertainment

Each

initializer clause

in a brace-enclosed initializer list is said to appertain to an element of the aggregate being initialized or to an element of one of its subaggregates.

Considering the sequence of initializer clauses, and the sequence of aggregate elements initially formed as the sequence of elements of the aggregate being initialized and potentially modified as described below:

For each initializer clause, if any of the following conditions is satisfied, it appertains to the corresponding aggregate element elem:

elem is not an aggregate.

The initializer clause begins with {.

The initializer clause is an expression, and an

implicit conversion sequence

can be formed that converts the expression to the type of elem.

elem is an aggregate that itself has no aggregate elements.

Otherwise, elem is an aggregate and that subaggregate is replaced in the list of aggregate elements by the sequence of its own aggregate elements, and the appertainment analysis resumes with the first such element and the same initializer clause. In other words, these rules apply recursively to the aggregate’s subaggregates.

The analysis is complete when all initializer clauses have been exhausted. If any initializer clause remains that does not appertain to an element of the aggregate or one of its subaggregates, the program is ill-formed.

structS1{inta,b;};structS2{S1s,t;};// Each subaggregate of “x” is appertained to an initializer clause starting with {S2x[2]={// appertains to “x[0]”{{1,2},// appertains to “x[0].s”{3,4}// appertains to “x[0].t”},// appertains to “x[1]”{{5,6},// appertains to “x[1].s”{7,8}// appertains to “x[1].t”}};// “x” and “y” have the same value (see below)S2y[2]={1,2,3,4,5,6,7,8};// The process of the appertainment analysis of “y”:// 1. Initializes the aggregate element sequence (x[0], x[1]) and// the initializer clause sequence (1, 2, 3, 4, 5, 6, 7, 8).// 2. Starting from the first elements of each sequence,// checks whether 1 appertains to x[0]:// · x[0] is an aggregate.// · 1 does not begin with {.// · 1 is an expression, but it cannot be implicitly converted to S2.// · x[0] has aggregate elements.// 3. 0 cannot appertain to x[0], therefore x[0] is replaced by x[0].s and x[0].t,// the aggregate element sequence becomes (x[0].s, x[0].t, x[1]).// 4. Resumes the appertainment check, but 1 cannot appertain to x[0].s either.// 5. The aggregate element sequence now becomes (x[0].s.a, x[0].s.b, x[0].t, x[1]).// 6. Resumes the appertainment check again:// 1 appertains to x[0].s.a, and 2 appertains to x[0].s.b.// 7. The rest of the appertainment analysis works similarly.charcv[4]={'a','s','d','f',0};// Error: too many initializer clausesCharacter arrays

Arrays of ordinary character types (char, signedchar, unsignedchar), char8_t(since C++20), char16_t, char32_t(since C++11), or wchar_t can be initialized from ordinary

string literals

, UTF-8 string literals(since C++20), UTF-16 string literals, UTF-32 string literals(since C++11), or wide string literals, respectively, optionally enclosed in braces. Additionally, an array of char or unsignedchar may be initialized by a UTF-8 string literal, optionally enclosed in braces(since C++20). Successive characters of the string literal (which includes the implicit terminating null character) initialize the elements of the array, with an

integral conversion

if necessary for the source and destination value(since C++20). If the size of the array is specified and it is larger than the number of characters in the string literal, the remaining characters are zero-initialized.

chara[]="abc";// equivalent to char a[4] = {'a', 'b', 'c', '\0'};// unsigned char b[3] = "abc"; // Error: initializer string too longunsignedcharb[5]{"abc"};// equivalent to unsigned char b[5] = {'a', 'b', 'c', '\0', '\0'};wchar_tc[]={L"кошка"};// optional braces// equivalent to wchar_t c[6] = {L'к', L'о', L'ш', L'к', L'а', L'\0'};Notes

An aggregate class or array may include non-aggregate public bases(since C++17), members, or elements, which are initialized as described above (e.g. copy-initialization from the corresponding initializer clause).

Until C++11, narrowing conversions were permitted in aggregate initialization, but they are no longer allowed.

Until C++11, aggregate initialization could only be used in variable definition, and could not be used in a

constructor initializer list

, a

new-expression

, or temporary object creation due to syntax restrictions.

In C, character array of size one less than the size of the string literal may be initialized from a string literal; the resulting array is not null-terminated. This is not allowed in C++.

Out-of-order designated initialization, nested designated initialization, mixing of designated initializers and regular initializers, and designated initialization of arrays are all supported in the

C programming language

, but are not allowed in C++.

structA{intx,y;};structB{structAa;};structAa={.y=1,.x=2};// valid C, invalid C++ (out of order)intarr[3]={[1]=5};// valid C, invalid C++ (array)structBb={.a.x=0};// valid C, invalid C++ (nested)structAa={.x=1,2};// valid C, invalid C++ (mixed)(since C++20)Feature-test macro ValueStdFeature

__cpp_aggregate_bases

201603L

(C++17)Aggregate classes with base classes

__cpp_aggregate_nsdmi

201304L

(C++14)Aggregate classes with default member initializers

__cpp_aggregate_paren_init

201902L

(C++20)Aggregate initialization in the form of

direct initialization

__cpp_char8_t

202207L

(C++23)
(DR20)char8_t compatibility and portability fix (

allow initialization of (unsigned char arrays

from

UTF-8 string literals

)

__cpp_designated_initializers

201707L

(C++20)Designated initializers

202606L

(C++29)Designated initializers for base class members Example

Run this code

#include<array>#include<cstdio>#include<string>structS{intx;structFoo{inti;intj;inta[3];}b;};intmain(){Ss1={1,{2,3,{4,5,6}}};Ss2={1,2,3,4,5,6};// same, but with brace elisionSs3{1,{2,3,{4,5,6}}};// same, using direct-list-initialization syntaxSs4{1,2,3,4,5,6};// error until CWG 1270:// brace elision only allowed with equals signintar[]={1,2,3};// ar is int[3]// char cr[3] = {'a', 'b', 'c', 'd'}; // too many initializer clausescharcr[3]={'a'};// array initialized as {'a', '\0', '\0'}intar2d1[2][2]={{1,2},{3,4}};// fully-braced 2D array: {1, 2}// {3, 4}intar2d2[2][2]={1,2,3,4};// brace elision: {1, 2}// {3, 4}intar2d3[2][2]={{1},{2}};// only first column: {1, 0}// {2, 0}std::array<int,3>std_ar2{{1,2,3}};// std::array is an aggregatestd::array<int,3>std_ar1={1,2,3};// brace-elision okay// int ai[] = {1, 2.0}; // narrowing conversion from double to int:// error in C++11, okay in C++03std::stringars[]={std::string("one"),// copy-initialization"two",// conversion, then copy-initialization{'t','h','r','e','e'}};// list-initializationunionU{inta;constchar*b;};Uu1={1};// OK, first member of the union// U u2 = {0, "asdf"}; // error: too many initializers for union// U u3 = {"asdf"}; // error: invalid conversion to int}// aggregatestructbase1{intb1,b2=42;};// non-aggregatestructbase2{base2():b3(42){}intb3;};// aggregate in C++17structderived:base1,base2{intd;};derivedd1{{1,2},{},4};// d1.b1 = 1, d1.b2 = 2, d1.b3 = 42, d1.d = 4derivedd2{{},{},4};// d2.b1 = 0, d2.b2 = 42, d2.b3 = 42, d2.d = 4Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior

CWG 413

C++98 anonymous bit-fields were initialized in aggregate initialization they are ignored

CWG 737

C++98 when a character array is initialized with a string literal
having fewer characters than the array size, the character
elements after the trailing '\0' was uninitialized they are
zero-initialized

CWG 1270

C++11 brace elision was only allowed to be used in copy-list-initialization allowed elsewhere

CWG 1518

C++11 a class that declares an explicit default constructor or
has inherited constructors should could be an aggregate it is not an
aggregate

CWG 1622

C++98 a union could not be initialized with {}allowed

CWG 2149

(

P3106R1

) C++98 it was unclear whether brace elision is
applicable during array size deduction applicable

CWG 2272

C++98 a non-static reference member that is not explicitly
initialized was copy-initialized from an empty initializer list the program is ill-
formed in this case

CWG 2610

C++17 aggregate types could not have private or protected indirect base classes allowed

CWG 2619

C++20 the kind of the initialization from designated initializers was unclear it depends on the
kind of the initializer

P2513R4

C++20 a UTF-8 string literal could not initialize an array of char
or unsignedchar, which was incompatible with C or C++17 such initialization
is valid See also

copy elision

initialization

constant initialization

list initialization

reference initialization

value initialization

zero initialization