Is the order of the initializers for a class\' constructor significant?
So say I have:
class MyClass : BaseClass
{
int a, b, c;
public:
The order does not matter for the compiler (the initialization order is always base classes first, and always base classes in the order of derivation, and members in the order of declaration), but it does matter for the reader: It is very confusing if the order in which you give the initializers does not match the order in which they are executed. While in most cases it doesn't matter, in some cases you can create subtle bugs, e.g.
struct Derived: Base
{
int member;
Derived();
}
Derived::Derived():
member(3),
Base(member) // This is executed *before* member is initialized!
{
}
This bug would stand out more clearly if the initializers were given in the correct order:
Derived::Derived():
Base(member), // Now we see immediately that member is uninitialized
member(3),
{
}
It doesn't matter in which order you list the initializers in the constructor initialization list. Members are initialized in the order they are declared and base(s) are initialized before members.
However, listing initializers in a different order that that can bite you if a subobject's initial value depends on the values of other subobjects.
class A
{
int y, x;
A(int x_value): x(x_value), y(x) {}
};
Since y is initialized before x, it gets a garbage value, and the order of the initializer list just hides the bug. That's why this deserves a compiler warning.
Would example 1 do something different to example 2?
No. Initialisation order is dictated by the standard, not by the order in which you write the initialisers:
[C++11: 12.6.2/10]:
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.
In fact, if you write them in any other order and one depends on the other, you may well be warned about it:
struct T {
std::vector<int> v;
int w;
T(int w) : w(w), v(0, w) {}
};
int main() {
T t(3);
}
// g++ 4.1.2:
// t.cpp: In constructor 'T::T(int)':
// Line 3: warning: 'T::w' will be initialized after
// Line 2: warning: '__gnu_debug_def::vector<int, std::allocator<int> > T::v'
// Line 5: warning: when initialized here