Search code examples
c++constructorinitialization

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


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

In other words, will the following code always print <unknown>, and the constructed class will have "known" as value for source_ (if the global variable something is true)?

class Foo {
  std::string source_;
public:
  Foo() : source_("<unknown>") {
    std::cout << source_ << std::endl;
    if(something){
      source_ = "known";
    }
  }
};

Solution

  • 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;
    }