4

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.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • @ShafikYaghmour: I don't really care for differences between the standards. It's the intention which matters, which is likely didn't change, only made clearer. – Yakov Galka Mar 11 '14 at 18:07
  • Makes sense, as far as I can tell the behavior should be the same and as you suggest *C++11* just made it explicit. – Shafik Yaghmour Mar 11 '14 at 19:23

2 Answers2

5

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.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
2

According to the C++ Standard

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

So at first there will be executed full expression a(f()) and after that the full expression b(g()) .

As the result output has to be

f0g1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335