Why Should I Initialize Member Variables in the Order They'Re Declared In

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.

Why C++ forces initialization of member variables to be in the order of the declaration

Constructors could be overloaded while destructor can't. If data members could be initialized in different order for different constructors, then the destructor can't guarantee to perform destruction on data members in the reverse order of their construction (for objects constructed by different constructors).

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.

What does Always initialize object members in the same order mean in regards to V8 optimizations?

V8 developer here. First off, this JavaScript performance advice is completely unrelated to C++'s rules for member initialization. It's also unrelated to the order of constructor arguments, i.e. the following would be perfectly fine from an engine performance point of view:

function Point(x, y) {
this.y = y; // Nothing wrong with this.
this.x = x;
}

What "initialize members in the same order" means is that all instances of that type should use the same initialization order. When they all use the same simple constructor, that happens automatically -- which is great, because that means in most cases, you don't have to worry about this; you don't even need to be aware of the advice.

The most common counter-example is creating objects using object literals, and not caring about the order of properties in there. Even if the set of property names is the same, order matters for hidden classes. Consider:

let p1 = {x: 1, y: 2};
let p2 = {y: 3, x: 4};
// p1 and p2 now have different hidden classes!
function get_x(point) { return point.x; }
get_x(point1);
get_x(point2);

The point.x load in get_x now needs to deal with two hidden classes,
which is slightly slower than seeing the same hidden class everytime.

"Always use a constructor" is a good rule of thumb to avoid this; however that's not quite precise enough, as the following example shows:

function SillyPoint(x, y) {
if (x >= y) { // or any other condition
this.x = x;
this.y = y;
} else {
this.y = y;
this.x = x;
}
}
let p1 = SillyPoint(1, 2);
let p2 = SillyPoint(2, 1);

Even though p1 and p2 used the same constructor, they initialized their
members in different order, so they have different hidden classes.
Like in the example above, this makes property loads slightly slower in functions that need to deal with both p1 and p2.

c++ class member initialization sequence

The rules for class initialization are spelled out in [class.base.init]/11

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).

8 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 ]

emphasis mine

So when we look at bullet 3 it specifically states that the member are constructed in the order the appear in the definition. This means that regardless of private, public, or how they are listed in the class member initialization list they will be constructed in the order they are declared.

Is the order of variable used in constructor initialization list important?

Do we have to use variables in initialization list in the same order as we declared in class?

Order of initialization list doesn't have impact on initialization order. So it avoids misleading behavior to use real order in initialization list.

Problem comes when there is dependencies:

class A 
{
int a;
double b;
float c;
// initialization is done in that order: a, b, c
A():a(1), c(2), b(c + 1) // UB, b is in fact initialized before c
{}
};

Will the order of variables in initialization list has any impact on memory allocation of that class/variables?

Order of initialization list doesn't have impact on layout or in initialization order.

Order of In Class Initialization versus Constructor Initialization List

This is guaranteed by the standard that non-static data members will be initialized in the order of their declarations in the class definition. How they're initialized (via default member initializer or member initializer list) and the order of these initializers don't matter.

[class.base.init]#13.3

(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).

[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. — end note ]

That means, the initialization order will always be ptr -> m1 -> m2.

Class member initialization order, C++

Whats the difference of written code and the one with same order in which they are declared???

If members don't depend on each other's initialization order, there is no difference whatsoever. But if they do, then a member initialization list may be telling a lie.

Many a programmer were bitten by this, when they thought their constructors were written correctly, but in fact they had undefined behavior on their hands.

Consider this simple case:

struct foo {
int _a;
int _b;
foo(int b) : _b(b), _a(2 * _b) {}
};

What's _a in the above example? If you answer anything but "the behavior is undefined because _b is used initialized", you'd be wrong.



Related Topics



Leave a reply



Submit