Order of Execution in Constructor Initialization List

Order of execution in constructor initialization list

According to ISO/IEC 14882:2003(E) section 12.6.2:

Initialization shall proceed in the following order:

  • First, and only for the constructor of the most derived class as described below, virtual base classes shall
    be 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 class names in the derived
    class base-specifier-list.
  • Then, direct base classes shall be initialized in declaration order as they appear in the base-specifier-list
    (regardless of the order of the mem-initializers).
  • Then, nonstatic data members shall be initialized in the order they were declared in the class definition
    (again regardless of the order of the mem-initializers).
  • Finally, the body of the constructor is executed.

So, follow that order, and you'll have your order. Also according to the standard, the order is prescribed as such so that objects can be uninitialized in the precisely reverse order.

constructor initialization list execution order with delegated constructors

§12.6.2/6 says

If a mem-initializer-id designates the constructor’s class,
it shall be the only mem-initializer... Once the target constructor returns, the body of the
delegating constructor is executed.

So there's no conflict, since you can't initialise anything before you delegate a constructor. Delegating a constructor simply calls that constructor, the target constructor's initialiser list is run, the target constructor runs, and then the principal constructor runs.

Is the order of variable used in constructor initialization list important?

Do we have to use variables in initialization list in the same order as we declared in class?

Order of initialization list doesn't have impact on initialization order. So it avoids misleading behavior to use real order in initialization list.

Problem comes when there is dependencies:

class A 
{
int a;
double b;
float c;
// initialization is done in that order: a, b, c
A():a(1), c(2), b(c + 1) // UB, b is in fact initialized before c
{}
};

Will the order of variables in initialization list has any impact on memory allocation of that class/variables?

Order of initialization list doesn't have impact on layout or in initialization order.

Is the order of initialization guaranteed by the standard?

I don't have the standard handy right now so I can't quote the section, but structure or class member initialisation always happens in declared order. The order in which members are mentioned in the constructor initialiser list is not relevant.

Gcc has a warning -Wreorder that warns when the order is different:


-Wreorder (C++ only)
Warn when the order of member initializers given in the code does
not match the order in which they must be executed. For instance:

struct A {
int i;
int j;
A(): j (0), i (1) { }
};

The compiler will rearrange the member initializers for i and j to
match the declaration order of the members, emitting a warning to
that effect. This warning is enabled by -Wall.

Why must initializer list order match member declaration order?

The warning is trying to prevent situations where you might be relying on the wrong ordering of the data members. Say you think B is initialized before A, and then you do something like this:

myClass::myClass() :
B(42), A(B) {}

Here, you have undefined behaviour because you are reading from an uninitialized B.

Member initializer list. Order of arguments evaluation

No, this evaluation order that would potentially cause you to leak is guaranteed not to happen. The expression within each mem-initializer is a full-expression ([intro.execution] §5.3). And [intro.execution] §9 tells us

Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.

So in other words, the evaluation of each expression used to initialize a member is completed before evaluation of the expression for the next member starts.

Dart constructor initialization order

I don't think there is an order defined between x and f and if it were, it wouldn't matter. You can't access x or f from anywhere until after suber.initB(b) completed and the constructor body of Point started to be executed.

Besides that the order you derived is correct.

Are initializer lists called before or after default constructors?

The non-static non-variant data members of a class are initialized in declaration order, without exception. The fact that you haven't specified a mem-initializer for beta_ simply means that it will be default-initialized, and this default initialization takes place before the initialization of gamma_ because beta_ precedes gamma_ in declaration order.

Besides that, even if you changed the order of beta_ and gamma_ in the class definition, there's nothing wrong with passing around a pointer to an object that hasn't been initialized yet.

Will the initialization list always be processed before the constructor code?

Yes, it will, as per C++11: 12.6.2 /10 (same section in C++14, 15.6.2 /13 in C++17):


In a non-delegating constructor, initialization proceeds in the following order (my bold):

  • First, and only for the constructor of the most derived class (1.8), 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 class base-specifier-list.

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

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

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


The main reason for using init-lists is to help the compiler with optimisation. Init-lists for non-basic types (i.e., class objects rather than int, float, etc.) can generally be constructed in-place.

If you create the object then assign to it in the constructor, this generally results in the creation and destruction of temporary objects, which is inefficient.

Init-lists can avoid this (if the compiler is up to it, of course but most of them should be).

The following complete program will output 7 but this is for a specific compiler (CygWin g++) so it doesn't guarantee that behaviour any more than the sample in the original question.

However, as per the citation in the first paragraph above, the standard does actually guarantee it.

#include <iostream>
class Foo {
int x;
public:
Foo(): x(7) {
std::cout << x << std::endl;
}
};
int main (void) {
Foo foo;
return 0;
}


Related Topics



Leave a reply



Submit