logo
Send your CVContact

/

logo
Background image

Blog

Initialization order

Dawid Trendota 20.08.2018

The order in which objects are initialized in C++ is a long and river-wide theme. It is worth getting acquainted with it more closely, because the constructor and destructor are indispensable tools in the workshop of any C++ programmer. It is also one of the most frequently asked recruitment questions for both junior and senior positions.

I divided the article into several parts. Because developers are reluctant to use articles that do not contain source code, each fragment will be based on an example.

Initialize class instances

Let’s start with a simple example before we reach for more complex structures.

<iostream>#include
 
using namespace std;
 
Chocolate class
{
public:
    Chocolate() { 
    	< "Chocolate ctor"  < endl; 
    }
    ~Chocolate() {
        cout  < "Chocolate dtor"  cout < endl;
    }
};

int main(int argc, char *argv) {
    Ch[]ocolate chocolate;
    return 0;
} </iostream>

Of course, the chocolate object will be first created and then destroyed. Like all variables with automatic storage duration, the time of his life is determined by the buckles around him. The outcome of the programme is unlikely to come as a surprise.

Chocolate ctor
Chocolate dtor

No one expected us to go first. What are the relationships between a class and its components?

Initialization of class components

We will use the Chocolate class from the previous example. This time it will be part of the ChocolateCake class.

<iostream>#include
 
using namespace std;
 
Chocolate class
{
public:
    Chocolate() { 
    	< "Chocolate ctor"  < endl; 
    }
    ~Chocolate() {
        cout  < "Chocolate dtor"  < endl;
    }
};

class ChocolateCake
{
public:
    ChocolateCake() {
        cout  cout < "ChocolateCake ctor"  < endl;
    }
    ~ChocolateCake() {
        cout  < "ChocolateCake dtor"  < endl;
    }
private:
    Chocolate chocolate;
};

int main(int argc, char *argv) {
    Cho[]colateCake cake;
    return 0;
} </iostream>

This case is already a little more complex. This time, we create an object that contains a different one. We expect to create both. And if you create it and destroy it. Just in what order? Let’s approach the topic intuitively, do we have access to its components in the object builder?

Of course they do.

So they had to be initialised earlier. What about destruction? Do we have access to class fields in the destructor? We have too. So they need to be destroyed later. The outcome of the programme should therefore not come as a surprise.

Chocolate ctor
ChocolateCake ctor
ChocolateCake dtor
Chocolate dtor

It is worth remembering here a certain rule of thumb. Destruction is reversed than construction. Another topic that we will discuss will be the relationship of initialization in the event of inheritance.

Initialize base classes

Let us deprive our class of its constituents in order to simplify the next example.

<iostream>#include
 
using namespace std;

ChocolateCake class
{
public:
    ChocolateCake() {
        < "ChocolateCake ctor"  < endl;
    }
    ~ChocolateCake() {
        cout  < "ChocolateCake dtor"  < endl;
    }
};

class BirthdayCake : public ChocolateCake
{
public:
    BirthdayCake() {
        cout  cout < "BirthdayCake ctor"  < endl;
    }
    ~BirthdayCake() {
        cout  < "BirthdayCake dtor"  < endl;
    }
};
 
int main(int argc, char *argv) {
    Bir[]thdayCake birthdayCake;
    return 0;
} </iostream>

Our new BirthdayCake class inherits from ChocolateCake. Of course, both constructors must be called. The order can be re-inferred. Do we have access to base class fields and methods in the BirthdayCake constructor?

Of course they do.

The constructor of this class had to be called before. The order of destruction can also be justified. Or invoke the rule regarding the order of construction/destruction. The result of the programme is as follows:

ChocolateCake ctor
BirthdayCake ctor
BirthdayCake dtor
ChocolateCake dtor

A summary of the

Let’s combine the previous examples. Let’s create two classes, derived and base. Each of them will have a component. It’s a task you’d expect to see in a conversation.

<iostream>#include
 
using namespace std;
 
Chocolate class
{
public:
    Chocolate() { 
    	< "Chocolate ctor"  < endl; 
    }
    ~Chocolate() {
        cout  < "Chocolate dtor"  < endl;
    }
};
 
class ChocolateCake
{
public:
    ChocolateCake() {
        cout  cout < "ChocolateCake ctor"  < endl;
    }
    ~ChocolateCake() {
        cout  < "ChocolateCake dtor"  < endl;
    }
private:
    Chocolate chocolate;
};
 
class Candles
{
public:
    Candles() {
        cout  < "Candles ctor"  < endl;
    }
    ~Candles() {
        cout  < "Candles dtor"  < endl;
    }
};
 
class BirthdayCake : public ChocolateCake
{
public:
    BirthdayCake() {
        cout  < "BirthdayCake ctor"  < endl;
    }
    ~BirthdayCake() {
        cout  < "BirthdayCake dtor"  < endl;
    }
private:
    Candles candles;
};
 
int main(int argc, char *argv) {
    Bir[]thdayCake birthdayCake;
    return 0;
} </iostream>

Ideone example


We will be asked about the result of the program, or more precisely about the order in which constructors and destructors are called. Combining the conclusions of previous examples, we will easily come to such an order:

Design:

  • base class component constructors
  • base class constructor
  • class component constructors
  • class constructor

Destruction:

  • class destructor
  • class destructors
  • base class destructor
  • component destructors of the base class

It is already a pure formality to indicate the outcome of the programme.

Chocolate ctor
ChocolateCake ctor
Candles ctor
BirthdayCake ctor
BirthdayCake dtor
Candles dtor
ChocolateCake dtor
Chocolate dtor

Does this example exhaust the subject? Unfortunately not quite. There are a few open points left:
– global variables,
– static variables,
– static class fields,
– the order in which multiple component fields are initialised,
– variables in the thread’s local memory,
– multiple and virtual inheritance.

However, this is already the material for the next article.

logo
ContactSend CV