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.
Related
In the following example below (c++11):
#include <iostream>
struct foo {
foo() = default;
foo(int x): v1{x} {}
int v1 = 0;
int v2 {v1};
void print() const {
std::cout<<"v1:"<<v1<<" v2:"<<v2<<std::endl;
}
};
int main() {
const auto bar1 = foo();
bar1.print(); // prints v1:0 v2:0
const auto bar2 = foo(42);
bar2.print(); // prints v1:42 v2:42
}
I understand about the rule of v1. bar1.v1 is default initialized, and bar2.v1 is intialized by the constructor, with default initializer ignored.
What I am curious about is v2, even though bar2.v2 is default initialized, it will use the v1 that is initialized by the constructor. My question is: is this the correct behavior according to c++ standard? I cannot seem to find a good source for this.
Whether default initialized or initialized in the member initializer list, the member variables are initialized in the order of declaration, so yes, this is exactly how it should be.
class.base.init/13:
13 In a non-delegating constructor, initialization proceeds in the following order:
(13.1)
First, and only for the constructor of the most derived class ([intro.object]), 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.
(13.2)
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).
(13.3) 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).
(13.4)
Finally, the compound-statement of the constructor body is executed.
[Note 6: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. — end note]
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.
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?
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
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.
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.
class D: A
{
B obj;
C obj2;
}
What order of construction here is guaranteed?
I know that D will be constructed after A, B and C, but what I really want to know is whether A is guaranteed to be constructed before B or C, or even whether B is guaranteed to be constructed before C.
I know you can have an explicit initialiser list:
D(): A(), B(), C()
{}
but does that initialiser list determine the order of initialisation?
Also, does whether or not any of the components do or don't have a default constructor?
From the C++03 standard ISO/IEC 14882:2003(E) §12.6.2/5 [class.base.init]:
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.
[Note: the declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. ]
So in this case, you are guaranteed that the order of initialization will be first the base class A, then the subobject B (since it appears first in the list of class members in the class definition), then the subobject C. The order of the initializer list is irrelevant, as is whether or not any of the members do or do not have a default constructor—if a member does not have a default constructor and it is not explicitly initialized in an initializer list, then it has an unspecified value.
but does that initialiser list determinethe ORDER of initialisation?
No. Initialization-list doesn't determine the the order of initialization of member data and the base subobject(s). Members are initialized in order of their declaration, and base subobjects are constructed in the order of their mention - from left to right:
struct A : B, C {} //B is constructed before C
Also, the base subobjects are constructed before the initialization of the member data.
struct A : B, C
{
D d;
E e;
};
Order of initialization in the above struct:
B => C => d => e
subobject subobject member member
And they're destructed in the reverse order.
Perhaps this example of broken code will help illustrate:
If I define a class like so:
class Connection {
boost::asio::tcp::ip::socket _socket;
boost::asio::io_service _io_service;
Connection() : _io_service(), _socket(_io_service)
{
}
};
This will fail in all modern compilers. Because _socket is defined first as a class member, the initialization list will try to initialize it first, despite the fact that the initialization list asks the compiler to initialize _io_service first. But since _io_service has not yet been initialized (the socket constructor depends on an initialized _io_service), the initialization of _socket will cause a segfault.
Perhaps somebody can quote the appropriate section of the standard that dictates this behaviour.
For the second half of the question, base classes will always be initialized before the classes own members.