Why Must Initializer List Order Match Member Declaration Order

Why must initializer list order match member declaration order?

The warning is trying to prevent situations where you might be relying on the wrong ordering of the data members. Say you think B is initialized before A, and then you do something like this:

myClass::myClass() :
B(42), A(B) {}

Here, you have undefined behaviour because you are reading from an uninitialized B.

Constructor initialization-list evaluation order

It depends on the order of member variable declaration in the class. So a_ will be the first one, then b_ will be the second one in your example.

Why should I initialize member variables in the order they're declared in?

The reason is because they're initialized in the order they're declared in your class, not the order you initialize them in the constructor and it's warning you that your constructor's order won't be used.

This is to help prevent errors where the initialization of b depends on a or vice-versa.

The reason for this ordering is because there is only one destructor, and it has to pick a "reverse order" to destroy the class member. In this case, the simplest solution was to use the order of declaration within the class to make sure that attributes were always destroyed in the correct reverse order.

Is the order of initialization guaranteed by the standard?

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.

Order of member initialization list

Initialization of member variables occurs in the order that they are declared in the class.

http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-order

and:

http://en.cppreference.com/w/cpp/language/initializer_list

3) Then, non-static data members are initialized in order of
declaration in the class definition.

Order of execution in constructor initialization list

According to ISO/IEC 14882:2003(E) section 12.6.2:

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.

So, follow that order, and you'll have your order. Also according to the standard, the order is prescribed as such so that objects can be uninitialized in the precisely reverse order.

Constructor initializer list doesn't follow order

Is there any way i can make Base constructor get called after?

No. An object's constructor must construct its base classes before any named member variables.

I'm trying to get rid of all the init methods and their calls by putting them into constructor instead

That is a worthwhile effort!

I'll assume your real code variable is something more complex than an int. Because if it's an int, you could simply call Base(50).

You can use delagating constructors to prepare a variable before any constructor begins initialization.

class Derived : public Base
{
public:
// Generate an important value FIRST, and then delegate
// construction to a new constructor.
Derived() : Derived( GenerateSomethingComplex() ) {}

private:

// Here, we can honor constructing Base before Derived
// while "some value" has been procured in advance.
Derived( SomethingComplex&& var) :
Base( var ),
variable( std::move(var) )
{}

SomethingComplex variable;

};

Order of Initializer list in C++

class Z {
public:
Z() throw();
protected:
X x_;
Y y_;
};

Z::Z() throw() : y_(), x_(y_) {}

In Z, you declare x_ before y_. Therefore, x is constructed before y_ regardless of the order of your initializers.

And, initializing x_(y_) before y_ is constructed yields undefined behavior.


I expected above program to give seg fault

Undefined behavior is undefined. You should not expect anything in particular.

Why should I prefer to use member initialization lists?

For POD class members, it makes no difference, it's just a matter of style. For class members which are classes, then it avoids an unnecessary call to a default constructor. Consider:

class A
{
public:
A() { x = 0; }
A(int x_) { x = x_; }
int x;
};

class B
{
public:
B()
{
a.x = 3;
}
private:
A a;
};

In this case, the constructor for B will call the default constructor for A, and then initialize a.x to 3. A better way would be for B's constructor to directly call A's constructor in the initializer list:

B()
: a(3)
{
}

This would only call A's A(int) constructor and not its default constructor. In this example, the difference is negligible, but imagine if you will that A's default constructor did more, such as allocating memory or opening files. You wouldn't want to do that unnecessarily.

Furthermore, if a class doesn't have a default constructor, or you have a const member variable, you must use an initializer list:

class A
{
public:
A(int x_) { x = x_; }
int x;
};

class B
{
public:
B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list;
{ // it is an error not to do so
}
private:
A a;
const int y;
};


Related Topics



Leave a reply



Submit