[dcl.init] (original) (raw)

9 Declarations [dcl]

9.5 Initializers [dcl.init]

9.5.1 General [dcl.init.general]

The process of initialization described in [dcl.init] applies to all initializations regardless of syntactic context, including the initialization of a function parameter ([expr.call]), the initialization of a return value ([stmt.return]), or when an initializer follows a declarator.

[Note 1:

The rules in [dcl.init] apply even if the grammar permits only the brace-or-equal-initializer form of initializer in a given context.

— _end note_]

Except for objects declared with the constexpr specifier, for which see [dcl.constexpr], an initializer in the definition of a variable can consist of arbitrary expressions involving literals and previously declared variables and functions, regardless of the variable's storage duration.

[Example 1: int f(int);int a = 2;int b = f(a);int c(b); — _end example_]

[Note 3:

The order of initialization of variables with static storage duration is described in [basic.start]and [stmt.dcl].

— _end note_]

A declaration D of a variable with linkage shall not have an initializerif D inhabits a block scope.

Tozero-initializean object or reference of typeTmeans:

Todefault-initializean object of typeTmeans:

A class type T is const-default-constructible if default-initialization of T would invoke a user-provided constructor of T (not inherited from a base class) or if

If a program calls for the default-initialization of an object of a const-qualified type T,T shall be a const-default-constructible class type or array thereof.

Tovalue-initializean object of typeTmeans:

A program that calls for default-initialization or value-initialization of an entity of reference type is ill-formed.

[Note 4:

For every object with static storage duration, static initialization ([basic.start.static]) is performed at program startup before any other initialization takes place.

In some cases, additional initialization is done later.

— _end note_]

If no initializer is specified for an object, the object is default-initialized.

If the entity being initialized does not have class or array type, theexpression-list in a parenthesized initializer shall be a single expression.

The semantics of initializers are as follows.

Thedestination typeis the cv-unqualified type of the object or reference being initialized and thesource typeis the type of the initializer expression.

If the initializer is not a single (possibly parenthesized) expression, the source type is not defined.

An immediate invocation ([expr.const]) that is not evaluated where it appears ([dcl.fct.default], [class.mem.general]) is evaluated and checked for whether it is a constant expression at the point where the enclosing initializer is used in a function call, a constructor definition, or an aggregate initialization.

Initialization includes the evaluation of all subexpressions of each initializer-clause of the initializer (possibly nested within braced-init-lists) and the creation of any temporary objects for function arguments or return values ([class.temporary]).

If the initializer is a parenthesized expression-list, the expressions are evaluated in the order specified for function calls ([expr.call]).

An object whose initialization has completed is deemed to be constructed, even if the object is of non-class type or no constructor of the object's class is invoked for the initialization.

[Note 9:

Such an object might have been value-initialized or initialized by aggregate initialization ([dcl.init.aggr]) or by an inherited constructor ([class.inhctor.init]).

— _end note_]

Destroying an object of class type invokes the destructor of the class.

Destroying a scalar type has no effect other than ending the lifetime of the object ([basic.life]).

Destroying an array destroys each element in reverse subscript order.

A declaration that specifies the initialization of a variable, whether from an explicit initializer or by default-initialization, is called the initializing declaration of that variable.

[Note 10:

In most cases this is the defining declaration ([basic.def]) of the variable, but the initializing declaration of a non-inline static data member ([class.static.data]) can be the declaration within the class definition and not the definition (if any) outside it.

— _end note_]

9.5.2 Aggregates [dcl.init.aggr]

[Note 1:

Aggregate initialization does not allow accessing protected and private base class' members or constructors.

— _end note_]

The elements of an aggregate are:

When an aggregate is initialized by an initializer list as specified in [dcl.init.list], the elements of the initializer list are taken as initializers for the elements of the aggregate.

The explicitly initialized elementsof the aggregate are determined as follows:

For each explicitly initialized element:

For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:

If the aggregate is a union and the initializer list is empty, then

[Example 3:

struct S { int a; const char* b; int c; int d = b[a]; }; S ss = { 1, "asdf" };initializesss.awith 1,ss.bwith "asdf",ss.cwith the value of an expression of the formint{}(that is, 0), and ss.d with the value of ss.b[ss.a](that is, 's').

struct A { string a;int b = 42;int c = -1;};

A{.c=21} has the following steps:

— _end example_]

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.

An aggregate that is a class can also be initialized with a single expression not enclosed in braces, as described in [dcl.init].

The destructor for each element of class type other than an anonymous union member is potentially invoked ([class.dtor]) from the context where the aggregate initialization occurs.

[Note 4:

This provision ensures that destructors can be called for fully-constructed subobjects in case an exception is thrown ([except.ctor]).

— _end note_]

The number of elements ([dcl.array]) in an array of unknown bound initialized with a brace-enclosed initializer-listis the number of explicitly initialized elements of the array.

[Example 4:

int x[] = { 1, 3, 5 };declares and initializesxas a one-dimensional array that has three elements since no size was specified and there are three initializers.

— _end example_]

[Example 5:

Instruct X { int i, j, k; }; X a[] = { 1, 2, 3, 4, 5, 6 }; X b[2] = { { 1, 2, 3 }, { 4, 5, 6 } }; a and b have the same value.

— _end example_]

An array of unknown bound shall not be initialized with an empty braced-init-list {}.79

[Note 5:

A default member initializer does not determine the bound for a member array of unknown bound.

Since the default member initializer is ignored if a suitable mem-initializer is present ([class.base.init]), the default member initializer is not considered to initialize the array of unknown bound.

[Example 6: struct S { int y[] = { 0 }; }; — _end example_]

— _end note_]

[Note 6:

Static data members, non-static data members of anonymous union members, and unnamed bit-fields are not considered elements of the aggregate.

[Example 7: struct A { int i;static int s;int j;int :17;int k;} a = { 1, 2, 3 };

Here, the second initializer 2 initializesa.jand not the static data memberA​::​s, and the third initializer 3 initializes a.kand not the unnamed bit-field before it.

— _end example_]

— _end note_]

If a member has a default member initializer and a potentially-evaluated subexpression thereof is an aggregate initialization that would use that default member initializer, the program is ill-formed.

[Example 8: struct A;extern A a;struct A { const A& a1 { A{a,a} }; const A& a2 { A{} }; }; A a{a,a}; struct B { int n = B{}.n; }; — _end example_]

When initializing a multidimensional array, theinitializer-clause_s_initialize the elements with the last (rightmost) index of the array varying the fastest ([dcl.array]).

[Example 9:

int x[2][2] = { 3, 1, 4, 2 };initializesx[0][0]to3,x[0][1]to1,x[1][0]to4, andx[1][1]to2.

On the other hand,float y[4][3] = { { 1 }, { 2 }, { 3 }, { 4 } };initializes the first column ofy(regarded as a two-dimensional array) and leaves the rest zero.

— _end example_]

Each initializer-clause in a brace-enclosed initializer-listis said to appertainto 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, each initializer-clause appertains to the corresponding aggregate element if

Otherwise, the aggregate element 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.

[Note 7:

These rules apply recursively to the aggregate's subaggregates.

[Example 10:

Instruct S1 { int a, b; };struct S2 { S1 s, t; }; S2 x[2] = { 1, 2, 3, 4, 5, 6, 7, 8 }; S2 y[2] = { { { 1, 2 },{ 3, 4 } },{ { 5, 6 },{ 7, 8 } } }; x and y have the same value.

— _end example_]

— _end note_]

This process continues until 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.

[Example 11: char cv[4] = { 'a', 's', 'd', 'f', 0 }; — _end example_]

[Example 12:

float y[4][3] = { { 1, 3, 5 },{ 2, 4, 6 },{ 3, 5, 7 },};is a completely-braced initialization: 1, 3, and 5 initialize the first row of the arrayy[0], namelyy[0][0],y[0][1], andy[0][2].

Likewise the next two lines initializey[1]andy[2].

The initializer ends early and thereforey[3]'s elements are initialized as if explicitly initialized with an expression of the formfloat(), that is, are initialized with0.0.

In the following example, braces in theinitializer-listare elided; however theinitializer-listhas the same effect as the completely-bracedinitializer-listof the above example,float y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };

The initializer forybegins with a left brace, but the one fory[0]does not, therefore three elements from the list are used.

Likewise the next three are taken successively fory[1]andy[2].

— _end example_]

[Note 8:

The initializer for an empty subaggregate is needed if any initializers are provided for subsequent elements.

[Example 13: struct S { } s;struct A { S s1;int i1; S s2;int i2; S s3;int i3;} a = { { }, 0, s, 0 }; — _end example_]

— _end note_]

[Example 14: struct A { int i;operator int();};struct B { A a1, a2;int z;}; A a; B b = { 4, a, a };

Braces are elided around theinitializer-clauseforb.a1.i.

b.a1.iis initialized with 4,b.a2is initialized witha,b.zis initialized with whatevera.operator int()returns.

— _end example_]

[Note 9:

An aggregate array or an aggregate class can contain elements of a class type with a user-declared constructor ([class.ctor]).

Initialization of these aggregate objects is described in [class.expl.init].

— _end note_]

When a union is initialized with an initializer list, there shall not be more than one explicitly initialized element.

[Example 15: union u { int a; const char* b; }; u a = { 1 }; u b = a; u c = 1; u d = { 0, "asdf" }; u e = { "asdf" }; u f = { .b = "asdf" }; u g = { .a = 1, .b = "asdf" }; — _end example_]

[Note 11:

As described above, the braces around theinitializer-clausefor a union member can be omitted if the union is a member of another aggregate.

— _end note_]

9.5.3 Character arrays [dcl.init.string]

An array of ordinary character type ([basic.fundamental]),char8_t array,char16_t array,char32_t array, or wchar_t array may be initialized by an ordinary string literal, UTF-8 string literal, UTF-16 string literal, UTF-32 string literal, or wide string literal, respectively, or by an appropriately-typed string-literal enclosed in braces ([lex.string]).

Additionally, an array of char orunsigned charmay be initialized by a UTF-8 string literal, or by such a string literal enclosed in braces.

Successive characters of the value of the string-literalinitialize the elements of the array, with an integral conversion ([conv.integral]) if necessary for the source and destination value.

[Example 1:

char msg[] = "Syntax error on line %s\n";shows a character array whose members are initialized with astring-literal.

Note that because'\n'is a single character and because a trailing'\0'is appended,sizeof(msg)is25.

— _end example_]

There shall not be more initializers than there are array elements.

[Example 2:

char cv[4] = "asdf"; is ill-formed since there is no space for the implied trailing'\0'.

— _end example_]

If there are fewer initializers than there are array elements, each element not explicitly initialized shall be zero-initialized ([dcl.init]).

9.5.4 References [dcl.init.ref]

A variable whose declared type is “reference to T” ([dcl.ref]) shall be initialized.

[Example 1: int g(int) noexcept;void f() { int i;int& r = i; r = 1; int* p = &r; int& rr = r; int (&rg)(int) = g; rg(i); int a[3];int (&ra)[3] = a; ra[1] = i; } — _end example_]

A reference cannot be changed to refer to another object after initialization.

[Note 1:

Assignment to a reference assigns to the object referred to by the reference ([expr.assign]).

— _end note_]

Argument passing ([expr.call])and function value return ([stmt.return]) are initializations.

The initializer can be omitted for a reference only in a parameter declaration ([dcl.fct]), in the declaration of a function return type, in the declaration of a class member within its class definition ([class.mem]), and where theexternspecifier is explicitly used.

[Example 2: int& r1; extern int& r2; — _end example_]

Given types “cv1 T1” and “cv2 T2”, “cv1 T1” is to “cv2 T2” ifT1 is similar ([conv.qual]) to T2, orT1 is a base class of T2.

cv1 T1” is reference-compatiblewith “cv2 T2” if a prvalue of type “pointer to cv2 T2” can be converted to the type “pointer to cv1 T1” via a standard conversion sequence ([conv]).

In all cases where the reference-compatible relationship of two types is used to establish the validity of a reference binding and the standard conversion sequence would be ill-formed, a program that necessitates such a binding is ill-formed.

A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:

In all cases except the last (i.e., implicitly converting the initializer expression to the referenced type), the reference is said to bind directly to the initializer expression.

[Note 3:

[class.temporary] describes the lifetime of temporaries bound to references.

— _end note_]

9.5.5 List-initialization [dcl.init.list]

List-initialization is initialization of an object or reference from abraced-init-list.

Such an initializer is called an initializer list, and the comma-separatedinitializer-clause_s_of the initializer-listordesignated-initializer-clause_s_of the designated-initializer-listare called the elements of the initializer list.

An initializer list may be empty.

List-initialization can occur in direct-initialization or copy-initialization contexts; list-initialization in a direct-initialization context is calleddirect-list-initialization and list-initialization in a copy-initialization context is called copy-list-initialization.

Direct-initialization that is not list-initialization is calleddirect-non-list-initialization.

[Note 1:

List-initialization can be used

[Example 1: int a = {1}; std::complex<double> z{1,2};new std::vectorstd::string\{"once", "upon", "a", "time"}; f( {"Nicholas","Annemarie"} ); return { "Norah" }; int* e {}; x = double{1}; std::mapstd::string,int\ anim = { {"bear",4}, {"cassowary",2}, {"tiger",7} }; — _end example_]

— _end note_]

A constructor is an initializer-list constructor if its first parameter is of type std​::​initializer_list<E> or reference tocv std​::​initializer_list<E> for some type E, and either there are no other parameters or else all other parameters have default arguments ([dcl.fct.default]).

[Note 2:

Initializer-list constructors are favored over other constructors in list-initialization ([over.match.list]).

Passing an initializer list as the argument to the constructor template template<class T> C(T) of a class C does not create an initializer-list constructor, because an initializer list argument causes the corresponding parameter to be a non-deduced context ([temp.deduct.call]).

— _end note_]

The templatestd​::​initializer_list is not predefined; if a standard library declaration ([initializer.list.syn], [std.modules]) of std​::​initializer_list is not reachable from ([module.reach]) a use of std​::​initializer_list — even an implicit use in which the type is not named ([dcl.spec.auto]) — the program is ill-formed.

List-initialization of an object or reference of type cv T is defined as follows:

Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions ([temp.variadic]), are evaluated in the order in which they appear.

That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clausethat follows it in the comma-separated list of the initializer-list.

[Note 4:

This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of theinitializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call.

— _end note_]

An object of type std​::​initializer_list<E> is constructed from an initializer list as if the implementation generated and materialized ([conv.rval]) a prvalue of type “array of N const E”, where N is the number of elements in the initializer list; this is called the initializer list's backing array.

Each element of the backing array is copy-initialized with the corresponding element of the initializer list, and thestd​::​initializer_list<E> object is constructed to refer to that array.

[Note 5:

A constructor or conversion function selected for the copy needs to be accessible ([class.access]) in the context of the initializer list.

— _end note_]

If a narrowing conversion is required to initialize any of the elements, the program is ill-formed.

[Note 6:

Backing arrays are potentially non-unique objects ([intro.object]).

— _end note_]

The backing array has the same lifetime as any other temporary object ([class.temporary]), except that initializing aninitializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary.

[Example 12: void f(std::initializer_list<double> il);void g(float x) { f({1, x, 3});} void h() { f({1, 2, 3});} struct A { mutable int i;};void q(std::initializer_list<A>);void r() { q({A{1}, A{2}, A{3}});}

The initialization will be implemented in a way roughly equivalent to this:void g(float x) { const double __a[3] = {double{1}, double{x}, double{3}}; f(std::initializer_list<double>(__a, __a+3));} void h() { static constexpr double __b[3] = {double{1}, double{2}, double{3}}; f(std::initializer_list<double>(__b, __b+3));} void r() { const A __c[3] = {A{1}, A{2}, A{3}}; q(std::initializer_list<A>(__c, __c+3));} assuming that the implementation can construct an initializer_list object with a pair of pointers, and with the understanding that __b does not outlive the call to f.

— _end example_]

[Example 13: typedef std::complex<double> cmplx; std::vector<cmplx> v1 = { 1, 2, 3 };void f() { std::vector<cmplx> v2{ 1, 2, 3 }; std::initializer_list<int> i3 = { 1, 2, 3 };} struct A { std::initializer_list<int> i4; A() : i4{ 1, 2, 3 } {} };

For v1 and v2, the initializer_list object is a parameter in a function call, so the array created for{ 1, 2, 3 } has full-expression lifetime.

For i3, the initializer_list object is a variable, so the array persists for the lifetime of the variable.

For i4, the initializer_list object is initialized in the constructor's ctor-initializer as if by binding a temporary array to a reference member, so the program is ill-formed ([class.base.init]).

— _end example_]

A narrowing conversion is an implicit conversion

[Note 7:

As indicated above, such conversions are not allowed at the top level in list-initializations.

— _end note_]

[Example 14: int x = 999; const int y = 999;const int z = 99;char c1 = x; char c2{x}; char c3{y}; char c4{z}; unsigned char uc1 = {5}; unsigned char uc2 = {-1}; unsigned int ui1 = {-1}; signed int si1 = { (unsigned int)-1 }; int ii = {2.0}; float f1 { x }; float f2 { 7 }; bool b = {"meow"}; int f(int);int a[] = { 2, f(2), f(2.0) }; — _end example_]