Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 691
Winestone Avatar asked Apr 18 '17 18:04

Winestone


People also ask

Can you call functions in initializer list?

And if we use Initializer List there are only two function calls: copy constructor + destructor call.

How do initializer lists work?

An initializer list starts after the constructor name and its parameters. The list begins with a colon ( : ) and is followed by the list of variables that are to be initialized – all of​ the variables are separated by a comma with their values in curly brackets.

Does initializer list run before constructor?

As already answered, initialization lists get completely executed before entering the constructor block. So it is completely safe to use (initialized) members in the constructor body.

Is assigned in constructor body consider performing initialization in initialization list?

Note: It is mandatory that a reference or a const member must be intialized in a constructor initialization list. They cannot be 'assigned' in the body of the constructor.


2 Answers

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.

like image 116
NathanOliver Avatar answered Sep 19 '22 22:09

NathanOliver


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

That's true.

My interpretation of that constraint is that a cannot be initialized before b unless the evaluation of the initializer expression is complete before b is initialized.

I don't see anything in the standard that speaks of sequencing the evaluation of the expressions used to initialize non-static members. However, I see the following example in the C++11 Standard (12.6.2/12):

Names in the expression-list or braced-init-list of a mem-initializer are evaluated in the scope of the constructor for which the mem-initializer is specified. [ Example:

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) { } }; 

That won't be valid unless the evaluation of this->i is sequenced after i is initialized.

like image 42
R Sahu Avatar answered Sep 16 '22 22:09

R Sahu