3

Is the order of the initializers for a class' constructor significant?

So say I have:

class MyClass : BaseClass
{
      int a, b, c;

   public:
      MyClass(int);
}

e.g. 1:

MyClass::MyClass(int forBase) :
  a(7),
  b(14),
  c(28),
  BaseClass(forBase) { }

e.g. 2:

MyClass::MyClass(int forBase) :
  BaseClass(forBase),
  a(7),
  b(14),
  c(28) { }

Would example 1 do something different to example 2?

Samuel Harmer
  • 4,264
  • 5
  • 33
  • 67
  • I would be interested in a third case. Assume no base class. Does the order of initializing `a`, `b` and `c` matter? g++ emits a warning for this with `-Weffc++` (I think). – Benjamin Bannier Jan 13 '12 at 17:07
  • No it doesn't, what matters is the order of declaration, check out [this](http://stackoverflow.com/q/6515042/368167), there is a quote form the C++03 standard, I don't think it differs for C++11. – Tamer Shlash Jan 13 '12 at 17:13
  • @Mr.TAMER: You spotted a duplicate – Lightness Races in Orbit Jan 13 '12 at 17:26
  • @LightnessRacesinOrbit: I knew, and was going to state that but thought not to do because I thought someone will post a quote from the new standard and so the answer will be better than that, and I happened :) so I really think adding a link to this answer in that answer will be really nice :) – Tamer Shlash Jan 13 '12 at 17:29
  • @Mr.TAMER: The questions can be merged. Well, maybe. – Lightness Races in Orbit Jan 13 '12 at 17:32
  • 1
    FYI, `[C++03: 12.6.2/5]` has the same wording. :) – Lightness Races in Orbit Jan 13 '12 at 17:33
  • Possible duplicate of [Order of calling base class constructor from derived class initialization list](https://stackoverflow.com/questions/6247595/order-of-calling-base-class-constructor-from-derived-class-initialization-list) – Yusuf R. Karagöz Jan 17 '18 at 15:13

3 Answers3

10

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
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
5

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),
{
}
celtschk
  • 19,311
  • 3
  • 39
  • 64
  • some compilers emit warnings on higher warning levels if the initialization list is in the wrong order. – Mooing Duck Jan 13 '12 at 17:14
  • @MooingDuck: True. But if you are not aware of the problems this may cause, you might be inclined to ignore or disable that warning. – celtschk Jan 13 '12 at 17:19
  • 1
    If you're ignoring and disabling warnings that you don't understand, then you're doomed to failure regardless. – Lightness Races in Orbit Jan 13 '12 at 17:25
  • @LightnessRacesinOrbit: Of course. But you might think you understand it (you understand what it says, after all), but not really understand what's the problem (i.e. you might understand that the order of initialization does not depend on the order of initializers, but may think that it doesn't matter anyway ― it's an extra step to see that it makes it harder to see bugs). – celtschk Jan 13 '12 at 17:29
  • That'd still be a silly way to program. A warning means there's something that you _don't_ understand (or you made a mistake that you are able to identify). – Lightness Races in Orbit Jan 13 '12 at 17:35
  • @LightnessRacesinOrbit: I agree. People that write compilers do not put the warnings in for fun. It is best to take heed of them. – Ed Heal Jan 13 '12 at 17:47
  • Indeedly. Of course, I'm not claiming that the majority of people actually _do_ :( – Lightness Races in Orbit Jan 13 '12 at 17:48
  • @LightnessRacesinOrbit: Not always. I've found that some warnings give me more than 99% false positives (i.e. situations where I *do* understand why I get the warning, I *do* understand what might get wrong in general, I *do* understand that it's absolutely 100% impossible to get into that situation for the code in question, and changing the code to avoid the warning would only obfuscate it without bringing any advantage except for silencing the warning). – celtschk Jan 13 '12 at 17:50
  • You have more than 99% false positive warnings?! That means 99% of your code would not pass review were you in my team. That's ... worrying. Seems you're likely writing incredibly fragile code. Don't upgrade your toolchain! – Lightness Races in Orbit Jan 13 '12 at 17:58
  • Well, you should work on your reading comprehension (I didn't say anything about the proportion of *all* warnings; although I tend to produce code that gives very few warnings out of the box). Moreover you are jumping to conclusions, even after I explicitly said the exact opposite. For the record: Comparing two guaranteed positive numbers *always* is safe, even if one of them happens to be of signed and the other of unsigned type. – celtschk Jan 14 '12 at 01:54
  • It's a statistical inference. My reading comprehension is just fine. – Lightness Races in Orbit Jan 15 '12 at 14:28
  • Then you should work on your statistical inference. If some people don't work 99% of the time, it doesn't follow that 99% of all people are lazy. – celtschk Jan 15 '12 at 15:54
4

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.

UncleBens
  • 40,819
  • 6
  • 57
  • 90