12
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?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
matt
  • 4,042
  • 5
  • 32
  • 50

3 Answers3

10

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.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • to be clear, it's the order of declaration that controls order of initialization – Jeff Paquette Jun 29 '11 at 02:26
  • ok cool, what about base classes vs member objects, is one guaranteed to be initialization? I guess technically base classes are declared before members, so does that mean yes? :) – matt Jun 29 '11 at 02:28
  • The reason declaration controls init order is it prevents possible ambiguities. What if 2 ctors have init-lists in different orders. It's good practice to always keep the order consistent to avoid confusion. – seand Jun 29 '11 at 02:32
  • 9
    @seand: the other reason is that members are destructed in reverse order to their construction. If it were possible for different constructors (via their initializer lists) to construct the members in different orders, then the C++ implementation would have to store some secret data somewhere so that it knew what order to destroy them later. As it is, once an object is constructed the implementation can forget which constructor was used. – Steve Jessop Jun 29 '11 at 02:35
  • @Nawaz: Since you mentioned, order of initialization in Inheritance, it would be appropriate to have a mention about virtual base class and the order of initialization. – Alok Save Jun 29 '11 at 04:00
10

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.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
1

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.

J T
  • 4,946
  • 5
  • 28
  • 38
  • What do you mean "on modern compiler"? I'm working with C++ since at least TC3.0 and I can't remember a compiler which got initialization order wrong. – sbi Jun 29 '11 at 08:30