Reputation: 947
Consider the following (simplified) situation:
class Foo
{
private:
int evenA;
int evenB;
int evenSum;
public:
Foo(int a, int b) : evenA(a-(a%2)), evenB(b-(b%2)), evenSum(evenA+evenB)
{
}
};
When i instanciate Foo like this:
Foo foo(1,3);
then evenA is 0, evenB is 2, but will evenSum be initialized to 2?
I tried this on my current platform (iOS) and it seems to work, but I'm not sure whether this code is portable.
Thanks for your help!
Upvotes: 44
Views: 7911
Reputation: 677
The order in which initializers are called: Initialization order
The order of member initializers in the list is irrelevant: the actual order of initialization is as follows:
- If the constructor is for the most-derived class, virtual bases are initialized in the order in which they appear in depth-first left-to-right traversal of the base class declarations (left-to-right refers to the appearance in base-specifier lists)
- Then, direct bases are initialized in left-to-right order as they appear in this class's base-specifier list
- Then, non-static data member are initialized in order of declaration in the class definition.
- Finally, the body of the constructor is executed
So yes, your example will work, as long as evenA
and evenB
are declared before evenSum
Upvotes: 0
Reputation: 1668
Members are initialized in the order they're declared in the class definition. As long as your initializer list follows this order, it should be ok.
Upvotes: 8
Reputation: 272507
This is well-defined and portable,1 but it's potentially error-prone.
Members are initialized in the order they're declared in the class body, not the order they're listed in the initialization list. So if you change the class body, this code may silently fail (although many compilers will spot this and emit a warning).
In a non-delegating constructor, initialization proceeds in the following order:
- First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
- Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
- 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).
- Finally, the compound-statement of the constructor body is executed.
(Highlighting is mine.)
This section of the standard then goes on to give an example of using member variables to initialize other member variables.
Upvotes: 47
Reputation: 153919
Yes, provide they've already been constructed. Just don't forget
that the order of construction is the order of the declarations in the
class definition, not the order of the initializers in the
constructor. And that the compiler typically won't tell you if you use
a variable before it has been constructed. In your case, for example,
if you move evenSum
to the top of the class, you have undefined
behavior (because its initializer uses uninitialized members), even
though in your constructor, you initialize evenA
and evenB
lexically
before evenSum
.
Upvotes: 11
Reputation: 13877
This also compiled without error on g++ 4.0.3 (6 years old now).
I feel confident this will compile fine on any reasonably recent compiler.
Upvotes: -2