Files
2025-10-25 03:02:53 +03:00

20 KiB
Raw Permalink Blame History

[class.base.init]

11 Classes [class]

11.9 Initialization [class.init]

11.9.3 Initializing bases and members [class.base.init]

1

#

In the definition of a constructor for a class, initializers for direct and virtual base class subobjects and non-static data members can be specified by actor-initializer, which has the form

ctor-initializer:
mem-initializer-list

mem-initializer-list:
mem-initializer ...opt
mem-initializer-list , mem-initializer ...opt

mem-initializer:
mem-initializer-id ( expression-listopt )
mem-initializer-id braced-init-list

mem-initializer-id:
class-or-decltype
identifier

2

#

Lookup for an unqualified name in a mem-initializer-id ignores the constructor's function parameter scope.

[Note 1:

If the constructor's class contains a member with the same name as a direct or virtual base class of the class, amem-initializer-id naming the member or base class and composed of a single identifier refers to the class member.

Amem-initializer-id for the hidden base class can be specified using a qualified name.

— end note]

Unless themem-initializer-id names the constructor's class, a non-static data member of the constructor's class, or a direct or virtual base of that class, themem-initializer is ill-formed.

3

#

Amem-initializer-list can initialize a base class using any class-or-decltype that denotes that base class type.

[Example 1: struct A { A(); };typedef A global_A;struct B { };struct C: public A, public B { C(); }; C::C(): global_A() { } // mem-initializer for base A — end example]

4

#

If amem-initializer-id is ambiguous because it designates both a direct non-virtual base class and an indirect virtual base class, themem-initializer is ill-formed.

[Example 2: struct A { A(); };struct B: public virtual A { };struct C: public A, public B { C(); }; C::C(): A() { } // error: which A? — end example]

5

#

Actor-initializer may initialize a variant member of the constructor's class.

If actor-initializer specifies more than onemem-initializer for the same member or for the same base class, thector-initializer is ill-formed.

6

#

A mem-initializer-list can delegate to another constructor of the constructor's class using anyclass-or-decltype that denotes the constructor's class itself.

If amem-initializer-id designates the constructor's class, it shall be the only mem-initializer; the constructor is a delegating constructor, and the constructor selected by themem-initializer is the target constructor.

The target constructor is selected by overload resolution.

Once the target constructor returns, the body of the delegating constructor is executed.

If a constructor delegates to itself directly or indirectly, the program is ill-formed, no diagnostic required.

[Example 3: struct C { C( int ) { } // #1: non-delegating constructor C(): C(42) { } // #2: delegates to #1 C( char c ) : C(42.0) { } // #3: ill-formed due to recursion with #4 C( double d ) : C('a') { } // #4: ill-formed due to recursion with #3}; — end example]

7

#

Theexpression-list or braced-init-list in amem-initializer is used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of [dcl.init] for direct-initialization.

[Example 4: struct B1 { B1(int); /* ... / };struct B2 { B2(int); / ... */ };struct D : B1, B2 { D(int); B1 b; const int c;};

D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) { /* ... */ } D d(10); — end example]

[Note 2:

The initialization performed by each mem-initializer constitutes a full-expression ([intro.execution]).

Any expression in amem-initializer is evaluated as part of the full-expression that performs the initialization.

— end note]

A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.

8

#

A temporary expression bound to a reference member in a mem-initializer is ill-formed.

[Example 5: struct A { A() : v(42) { } // errorconst int& v;}; — end example]

9

#

In a non-delegating constructor other than an implicitly-defined copy/move constructor ([class.copy.ctor]), if a given potentially constructed subobject is not designated by amem-initializer-id (including the case where there is nomem-initializer-list because the constructor has noctor-initializer), then

if the entity is a non-static data member that has a default member initializer ([class.mem]) and either

the constructor's class is a union ([class.union]), and no other variant member of that union is designated by a mem-initializer-id or

the constructor's class is not a union, and, if the entity is a member of an anonymous union, no other member of that union is designated by amem-initializer-id,

the entity is initialized from its default member initializer as specified in [dcl.init];

otherwise, if the entity is an anonymous union or a variant member ([class.union.anon]), no initialization is performed;

otherwise, the entity is default-initialized ([dcl.init]).

[Note 3:

An abstract class ([class.abstract]) is never a most derived class, thus its constructors never initialize virtual base classes, therefore the corresponding mem-initializers can be omitted.

— end note]

An attempt to initialize more than one non-static data member of a union renders the program ill-formed.

[Note 4:

After the call to a constructor for classX for an object with automatic or dynamic storage duration has completed, if the constructor was not invoked as part of value-initialization and a member ofX is neither initialized nor given a value during execution of the compound-statement of the body of the constructor, the member has an indeterminate or erroneous value ([basic.indet]).

— end note]

[Example 6: struct A { A();};

struct B { B(int);};

struct C { C() { } // initializes members as follows: A a; // OK, calls A::A()const B b; // error: B has no default constructorint i; // OK, i has indeterminate or erroneous valueint j = 5; // OK, j has the value 5}; — end example]

10

#

If a given non-static data member has both a default member initializer and a mem-initializer, the initialization specified by themem-initializer is performed, and the non-static data member's default member initializer is ignored.

[Example 7:

Givenstruct A {int i = /* some integer expression with side effects */ ; A(int arg) : i(arg) { }// ...}; the A(int) constructor will simply initialize i to the value ofarg, and theside effects in i's default member initializer will not take place.

— end example]

11

#

A temporary expression bound to a reference member from a default member initializer is ill-formed.

[Example 8: struct A { A() = default; // OK A(int v) : v(v) { } // OKconst int& v = 42; // OK}; A a1; // error: ill-formed binding of temporary to reference A a2(1); // OK, unfortunately — end example]

12

#

In a non-delegating constructor, the destructor for each potentially constructed subobject of class type is potentially invoked ([class.dtor]).

[Note 5:

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

— end note]

13

#

In a non-delegating constructor, initialization proceeds in the following order:

  • (13.1)

    First, and only for the constructor of the most derived class ([intro.object]), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived classbase-specifier-list.

  • (13.2)

    Then, direct base classes are initialized in declaration order as they appear in thebase-specifier-list (regardless of the order of themem-initializers).

  • (13.3)

    Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of themem-initializers).

  • (13.4)

    Finally, the compound-statement of the constructor body is executed.

[Note 6:

The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization.

— end note]

14

#

[Example 9: struct V { V(); V(int);};

struct A : virtual V { A(); A(int);};

struct B : virtual V { B(); B(int);};

struct C : A, B, virtual V { C(); C(int);};

A::A(int i) : V(i) { /* ... / } B::B(int i) { / ... / } C::C(int i) { / ... */ } V v(1); // use V(int) A a(2); // use V(int) B b(3); // use V() C c(4); // use V() — end example]

15

#

[Note 7:

The expression-list or braced-init-list of a mem-initializer is in the function parameter scope of the constructor and can use this to refer to the object being initialized.

— end note]

[Example 10: class X {int a; int b; int i; int j;public:const int& r; X(int i): r(a), b(i), i(i), j(this->i) { }};

initializesX::r to refer toX::a, initializesX::b with the value of the constructor parameteri, initializesX::i with the value of the constructor parameteri, and initializesX::j with the value ofX::i; this takes place each time an object of classX is created.

— end example]

16

#

Member functions (including virtual member functions, [class.virtual]) can be called for an object under construction or destruction.

Similarly, an object under construction or destruction can be the operand of thetypeid operator ([expr.typeid]) or of adynamic_cast ([expr.dynamic.cast]).

However, if these operations are performed during evaluation of

a ctor-initializer (or in a function called directly or indirectly from actor-initializer) before all themem-initializers for base classes have completed,

a precondition assertion of a constructor, or

a postcondition assertion of a destructor ([dcl.contract.func]),

the program has undefined behavior.

[Example 11: class A {public: A(int);};

class B : public A {int j;public:int f(); B() : A(f()), // undefined behavior: calls member function but base A not yet initialized j(f()) { } // well-defined: bases are all initialized};

class C {public: C(int);};

class D : public B, C {int i;public: D() : C(f()), // undefined behavior: calls member function but base C not yet initialized i(f()) { } // well-defined: bases are all initialized}; — end example]

17

#

[Note 8:

[class.cdtor] describes the results of virtual function calls,typeid anddynamic_casts during construction for the well-defined cases; that is, describes the polymorphic behavior of an object under construction.

— end note]

18

#

A mem-initializer followed by an ellipsis is a pack expansion ([temp.variadic]) that initializes the base classes specified by a pack expansion in the base-specifier-list for the class.

[Example 12: template<class... Mixins>class X : public Mixins... {public: X(const Mixins&... mixins) : Mixins(mixins)... { }}; — end example]