Specifically, say I have:
struct X { X(int i) { cout << i; } };
int f() { cout << 'f'; return 0; }
int g() { cout << 'g'; return 1; }
struct Z {
Z() : a(f()), b(g()) {}
X a, b;
};
int main() { Z z; cout << '\n'; }
I know that the constructors of the members are guaranteed to be invoked in the order they are defined in the struct
, so 0
will be printed before 1
.
But how about the evaluation of their arguments? Is it guaranteed to be:
f0g1
? Or, perhaps,
fg01
and
gf01
are also valid outputs?
References to the standard are appreciated.
In C++11 draft standard each member initializer is a full-expression so all side effects have to take effect before the next one is evaluated.
Section 12.6.2
Initializing bases and members paragraph 7 says:
[...]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.[...]
and section 1.9
Program execution paragraph 14 says:
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.
The relevant grammar from section 12.6.2
is as follows:
ctor-initializer:
: mem-initializer-list
mem-initializer-list:
mem-initializer ...opt
mem-initializer , mem-initializer-list ...opt
[...]
Pre C++11 the same wording on each mem-initializer being a full-expression is not there, at least not in the oldest draft standard available 1804. But as far as I can tell the same logic I used in Are multiple mutations of the same variable within initializer lists undefined behavior pre C++11 applies in this case as well and so we should expect the same behavior pre C++11 as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With