
So, here is a small C ++ program:
#include <iostream>
class A {
private:
int a;
int b;
public:
A (int x): b (x), a (b) {}
void dump () {
std :: cout << "a =" << a << "b =" << b << std :: endl;
}
};
int main () {
A a (42);
a.dump ();
return 0;
}
If you think she will give out
a = 42 b = 42
That you are deceived, she will give out something like
')
a = 4379 b = 42
This will happen because the compiler will not initialize the variables in the order in which they are listed in the string
A (int x): b (x), a (b)
and first the variable “a” will be initialized, and only then the variable “b”. Since at the time of initialization “a”, the variable “b” still has an undefined value, then “a” will get an undefined value.
The situation becomes even more dramatic if we imagine that “a” and “b” are not just ints, but some complex objects, for which, say, the constructor parameters determine the amount of allocated memory. Then the rake can hit in the forehead very much.
And in what order is the initialization going?
In fact, the initialization order does not depend on the order in the string.
A (int x): b (x), a (b)
Everything is determined by the order of declarations:
int a;
int b;
If you rearrange these two lines in places, then the initialization order will change, and the designer will work correctly.
You can see this by playing with this example.
#include <iostream>
class S {
private:
int data;
public:
S (int x) {
std :: cout << "S (int x) x =" << x << std :: endl;
data = x;
}
S (S & x) {
std :: cout << "S (S & x) x.data =" << x.data << std :: endl;
data = x.data;
}
int dump () {
return data;
}
~ S () {
std :: cout << "~ S () x.data =" << this-> data << std :: endl;
}
};
class A {
private:
S a; // try rearranging
S b; // these two declarations
public:
A (int x): b (x), a (b) {}
void dump () {
std :: cout << "a =" << a.dump () << "b =" << b.dump () << std :: endl;
}
};
int main () {
A a (1);
a.dump ();
return 0;
}
But I gave this result:
S (S & x) x.data = 134515845
S (int x) x = 1
a = 134515845 b = 1
~ S () x.data = 1
~ S () x.data = 134515845
Notice that the “S (S & x)” constructor was first executed. If you rearrange the places of the declaration, then everything will work correctly.
What is it? Bug in C ++?
Of course not!
The fact is that when removing an object, all destructive actions must be carried out in the order strictly opposite to the order of construction. At the same time, C ++ allows the coexistence of several constructors. In what order to destroy parts of an object, if the order of initialization in different constructors is different? Remembering how exactly the object was created can be quite expensive. Only one thing remains - to introduce a strict initialization order for all constructors that is not related to their code.
What was done.
And in order not to accidentally step on these rakes, it is better to always describe initialization in the same order in which the members of the class are declared.
Successes to all!
upd: there is a standard for this
here point 12.6.2 # 5 p 197.
upd2: or
http://www.kuzbass.ru:8086/docs/isocpp/special.html#class.base.init (thanks to EntropiouS)