Search code examples
c++language-lawyerundefined-behavioroperator-precedenceinitialization-order

Are functions calls in a constructor's initializer-list sequenced?


Consider:

int f () {
    static int i = 0;
    return i++;
}

struct Test {
    int a, b;
    Test () : a(f()), b(f()) {}
};

Test t;

I know that a is initialized before b due to the order of their declaration in the struct.

I also know that the two calls to f in g(f(), f()) are unsequenced.

So I am wondering if it is guaranteed that t.a == 0 and t.b == 1?


Solution

  • So I am wondering if it is guaranteed that t.a == 0 and t.b == 1?

    This will always be true so long as a comes before b in the class declaration and nothing else calls f() between the initialization of a and b. Class members are initialized in the order they are declared in the class. [class.base.init]/11:

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

    • 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).

    So since a comes before b then when the constructor initializes a it will call f() the first time and then it will call it a second time when it initializes b.

    We also know there is a sequence point between member initializer because [class.base.init]/7:

    [...]The initialization performed by each mem-initializer constitutes a full-expression. Any expression in a mem-initializer is evaluated as part of the full-expression that performs the initialization.

    tells us each initializer is a full expression and each full expression is sequenced: [intro.execution]/14

    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.