Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does incrementing in a member initializer list generate undefined behavior?

Tags:

Is this causing undefined behaviour? Specifically, the incrementing in the initializer list and how will that be evaluated.

class Wrinkle { public:     Wrinkle(int i) : a(++i), b(++i), x(++i) {} private:     int a;     int x;     int b; }; 

The difference in order between the declaration of members and initializer list is intended since this is an example that would showcase exactly that difference, so please ignore it for now.

like image 281
TwoOfDiamonds Avatar asked Jan 19 '18 12:01

TwoOfDiamonds


2 Answers

The C++17 standard contains an example almost exactly the same as in the question:

struct B1 { B1(int); /* ... */ }; struct B2 { B2(int); /* ... */ }; struct D : B1, B2 {   D(int);   B1 b;   const int c; };  D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) { /* ... */ } D d(10); 

This is followed by a note:

[ Note: The initialization performed by each mem-initializer constitutes a full-expression (4.6). Any expression in a mem-initializer is evaluated as part of the full-expression that performs the initialization. — end note ]

Following the link, section 4.6 tells us that one of the definitions of "full-expression" is

... a mem-initializer, including the constituent expressions of the initializer,

The phrase "including constituent expressions of the initiailizer" strongly suggests to me that the above code is legal, because the side effects of ++i will have completed before moving on to the next initializer. This is just my reading of the standard though, I'm happy to defer to anyone with more standardese experience than me.

(It's also worth noting that initialization of members will happen in the order in which they are declared in the class, not in the order in which they appear in the member initializer list).

like image 40
Tristan Brindle Avatar answered Oct 16 '22 04:10

Tristan Brindle


This does not generate Undefined Behavior because:

[class.base.init]#7

[ Note: 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. ]

[intro.execution]

5. A full-expression is

  • [...]
  • an init-declarator or a mem-initializer, including the constituent expressions of the initializer,

9. 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.


But beware that:

[class.base.init]#13

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 your code will effectively assign i + 1 to a, i + 2 to x and i + 3 to b.

like image 185
Holt Avatar answered Oct 16 '22 04:10

Holt