Order of member initializers [duplicate] - c++

This question already has answers here:
Initialization Order of Class Data Members
(2 answers)
Closed 5 years ago.
Following code gives correct output, If I declare variables i and j, Like int i, j;
class A
{
int i, j;
public:
A(int val) : i(val), j(i + 1)
{
cout<<i<<endl<<j<<endl;
}
};
But If I declare variable i and j, like int j, i;. then j print garbage value.
class A
{
int j, i;
public:
A(int val) : i(val), j(i + 1)
{
cout<<i<<endl<<j<<endl;
}
};
So, Is it depend on order of declaration of variables?

Is it depend on order of declaration of variables?
Yes, the data members are always initialized in the order of their declarations, which has nothing to do with the order of the member initializer lists.
That means for your 2nd code snippet, j is always initialized before i; but when it's initialized by member initializer i is still not initialized.
The complete initialization order for the object is:
(emphasis mine)
The order of member initializers in the list is irrelevant: the actual
order of initialization is as follows:
1) If the constructor is for the most-derived class, virtual base
classes 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)
2) Then, direct base classes are initialized in left-to-right order as
they appear in this class's base-specifier list
3) Then, non-static data members are initialized in order of
declaration in the class definition.
4) Finally, the body of the constructor is executed

Is it depend on order of declaration of variables?
Absolutely! The order in which initializers appear on the initialization list is disregarded by the standard; only the order of declaration matter. This is done so that "reverse order of initialization" be meaningful in the destructor, even though potentially there may be multiple constructors with initializer lists arranged in different order.
Here is the relevant portion of the C++ standard (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.
[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. — end note ]

Is it depend on order of declaration of variables?
Yes, the order in which data members (i.e.: i and j in your class A) are initialized, corresponds to the order in which they are declared and not the order as they appear in the constructor's member initializer list.
Your constructor's member initializer list in class A
A(int val) : i(val), j(i + 1)
says nothing about the order in which these data members are initialized.
The data member j will still be initialized before i if j is declared before i (i.e.: int j, i). In that case j is being initialized to i + 1, but i is uninitialized at this moment, which may result in j containing garbage.
In GCC you can get a warning being displayed in these cases by providing the -Wreorder option, which is already enabled by passing the -Wall option.

Related

C++ can I initialize member variable based on a just initialized another member variable? [duplicate]

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!
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).
1. From [class.base.init] in the C++ standard(s):
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.
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.
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.
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
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.

Initializing constructor elements with other constructor elements [duplicate]

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!
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).
1. From [class.base.init] in the C++ standard(s):
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.
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.
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.
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
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.

Is using a default member initializer with a previously default member-initialized variable legal? [duplicate]

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!
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).
1. From [class.base.init] in the C++ standard(s):
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.
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.
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.
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
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.

Initialization order for nonstatic/static/global/subclass members

I deliberately create the following code to let me easily present the question.
Question> What is the initialization order of all variables?
#include <iostream>
int iGlobal = 10;
class A {
public:
A(int _a) : m_a_a(_a) {}
private:
int m_a_a;
};
class B : public A
{
public:
B() : m_b_b(40), A(20), m_b_a(30) {}
private:
static int m_b_static_a;
int m_b_a;
int m_b_b;
int m_b_c; // this variable is NOT initialized in the B::B() initialization list
static int m_b_static_b;
};
int B::m_b_static_a = 11;
int B::m_b_static_b = 12;
int main(void)
{
B b;
return 0;
}
First, I list all variables as follows:
iGlobal, m_a_a, m_b_static_a, m_b_a, m_b_b, m_b_c, m_b_static_b
Here is what I think I am right.
m_a_a < m_b_a < m_b_b < m_b_c (i.e. X < Y iff X is initialized early than Y)
m_b_static_a < m_b_static_b
Rule1> C++ guarantees that variables in compilation unit (.cpp file) are initialised in order of declaration.
Rule2> The order listed in the initialized list doesn't control the order of initialization.
I have problems to order among the global variable, static variable and non-static variable.
Within a compilation unit, globals are initialised in the same order they're declared. However, the order is unspecified across different compilation units (see What's the "static initialization order fiasco"?).
Class initialisation order:
Members of base classes (when inheritance is present)
Members of the current class
Constructor
Members initialisation respects the declaration order, regardless the order used in the initilisation list.
Having class C : public A, public B, initialiases A, then B, then C. And their destruction occurs in the inverse order.
NOTE: Virtual base classes do not respect the order mentioned above.
Quoting §12.6.2/5 from the C++03 Standard:
Initialization shall proceed in the following order:
— First, and only for the constructor of the most derived class as
described below, virtual base classes shall be 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 class names in the derived class
base-specifier-list.
— Then, direct base classes shall be initialized in declaration order
as they appear in the base-specifier-list (regardless of the order of
the mem-initializers).
— Then, nonstatic data members shall be initialized in the order they
were declared in the class definition (again regardless of the order
of the mem-initializers).
— Finally, the body of the constructor is executed.
Concluding, the order will be:
iGlobal (global)
B::m_b_static_a (static)
B::m_b_static_b (static)
A::m_a_a (base class member)
B::m_b_a (class member)
B::m_b_b (class member)
No, all the "globals" will be initialized before main:
iGlobal, m_b_static_a, m_b_static_b, m_a_a, m_b_a, m_b_b, and m_b_c is never initialized.
The canonical initialization order is:
Base classes left-to-right
Nonstatic data members top-to-bottom
The body of the constructor
Here is the initialization order that I observed in VC++ 2005:
Global data (iGlobal == 10 before entering main())
Static data members (B::m_b_static_a == 11, B::m_b_static_b == 12 )
Base classes (A::m_a_a == 20)
Nonstatic data members in the initialization list (B::m_b_a == 30, B::m_b_b == 40)
B::m_b_c remains uninitialized (set to 0xcccccccc) after returning from B's constructor.

Is the order of initialization guaranteed by the standard?

In the following code snippet d1's initializer is passed d2 which has not been constructed yet (correct?), so is the d.j in D's copy constructor an uninitialized memory access?
struct D
{
int j;
D(const D& d) { j = d.j; }
D(int i) { j = i; }
};
struct A
{
D d1, d2;
A() : d2(2), d1(d2) {}
};
Which section of C++ standard discusses order of initialization of data members?
I don't have the standard handy right now so I can't quote the section, but structure or class member initialisation always happens in declared order. The order in which members are mentioned in the constructor initialiser list is not relevant.
Gcc has a warning -Wreorder that warns when the order is different:
-Wreorder (C++ only)
Warn when the order of member initializers given in the code does
not match the order in which they must be executed. For instance:
struct A {
int i;
int j;
A(): j (0), i (1) { }
};
The compiler will rearrange the member initializers for i and j to
match the declaration order of the members, emitting a warning to
that effect. This warning is enabled by -Wall.
The C++ standard (ISO/IEC 14882:2003 12.6.2/5, Initializing bases and members) says:
Initialization shall proceed in the following order:
— First, and only for the constructor of the most derived class as described below, virtual base classes shall be 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 class names in the derived
class base-specifier-list.
— Then, direct base classes shall be initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
— Then, nonstatic data members shall be initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
— Finally, the body of the constructor is executed.
Bullet point 3 guarantees the order of nonstatic data member initialization.
In your example it will fail:
struct A
{
D d1, d2;
A() : d2(2), d1(d2) {}
};
d1: is initialised first as it is declared first.
d2: is then initialized.
As a result the initializer list will construct d1 using a reference to an invalid object (d2).
This is one reason to turn up your compilers warning level as high as possable.
And additionaly force it to report all warnings as errors.
This phenomenon is explained/highlighted in Item 13 of Meyer's Effective C++. It says that the destructor must destroy elements in the inverse order of its constructors, therefore all constructors must initialize elements in the same order, therefore they initialize them in the order in which they're declared (instead of the sequence of the initialization lists).
Yes. A good compiler should warn you that A::d2 will be initialized after A::d1.