A problem of order - constructor initialization
Written by Alex Armstrong   
Article Index
A problem of order - constructor initialization
Solution

 

Solution

The key to finding the problem is to simply check the value of a and b in an instance of the class. The result for example obtained on one run was

 a=3795240 b=20   

This is clearly not right and the first value and the fact it was different each time the program is run suggests that a is being initialized with random crud.

The reason is that the background information provided at the start of this puzzle left out one important point that is often overlooked. The order that initializations are carried out isn't determined by the order that they are written in the initialization list but by the order in which the variables are declared. This is simple enough but when you look at:

MyClass(int value) : b(value*2),a(b)

you can't help but read the instructions in order and you mind just believes that this is the default flow of control. That is the list is equivalent to:

b=value*2;
a=b;

However what the compiler does is read the variable declarations and then apply the initialization you specified in the list. So in fact the declarations are re-written as:

int a=b;
int b=value*2;

And now you can see quite clearly where the undefined value comes from. Of course if you actually wrote the above you would get a compiler error that b wasn't defined but you usually don't get that error from an initialization list that implies the same thing.

Pattern

The best way of avoiding this sort of error is not to use constructor initialization lists at all but this is slightly restrictive. Initialization lists are more efficient than writing code into the body of the constructor in the case of object members. The reason is that putting assignments in to the body of the constructor first initializes everything to default values, using their default constructors and then applies the assignment initializers which creates a temporary object and then uses the object's assignment operator. For intrinsic types such as int there is no real difference between the two methods.

Also you cannot initialize const or reference members within the constructor bodies but you can in an initializer list.

A better rule might be not to reference variables being initialized as values of other variables in the list but once again there are time when it seems natural to do so. For example, if you initialize an object and then want to initialize another variable to reference some member of the first object. For example suppose we have:

class MyClass2
{
public:
int x;
MyClass2():x(3)
{
}
};

And then we use this in other class:

class MyClass
{
private:
MyClass2 myObj2;
int a;
public:
MyClass():a(myObj2.x)
{
}
};

This works fine and a is initialized to whatever myObj2.x is initialized to, i.e. 3 in this case. Now consider:

class MyClass
{
private:
int a;
MyClass2 myObj2;
public:
MyClass():a(myObj2.x)
{
}
};

This doesn't work because myObj2 isn't constructed at the point that the attempt is made to set a to myObj2.x.

Sometimes it just seems safer to always initialize in the constructor.

It is certainly worth remembering that the order of initialization is always the same as the order of declaration.


Banner

More Puzzles

Javascript
Stringy Objects

A Programmer's Puzzle in which we contemplate situations in which string equivalence in Javascript is clearly not what it seems - and explain why it all goes wrong.


C#
In-Place Or Operator Methods?

This particular C# puzzle is one of those that involves an error that no self respecting programmer would make... but are you so sure. If you use the DateTime class regularly then sure, you not only w [ ... ]


Javascript
The Undefined Defined Variable

Here's a teaser that poses a practical problem - one that's happened in everyday Javascript programming. See if you can work out the answer before looking at its solution and the pattern to follow to  [ ... ]


Other Articles

<ASIN:0132673266>

<ASIN:059600298X>

<ASIN:0321334876>

<ASIN:156592116X>