Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I was writing some code today and got a weird compile error, which seems to be caused by initializing member variables in a different order than they were declared.

Example:

class Test {
    int a;
    int b;

public:
    Test() : b(1), a(2) {
    }
};

int main() {
    Test test;
    return 0;
}

Then if I compile it with -Werror -Wall:

$ g++ -Werror -Wall test.cpp
test.cpp: In constructor ‘Test::Test()’:
test.cpp:3:9: error: ‘Test::b’ will be initialized after [-Werror=reorder]
test.cpp:2:9: error:   ‘int Test::a’ [-Werror=reorder]
test.cpp:6:5: error:   when initialized here [-Werror=reorder]
cc1plus: all warnings being treated as errors

I realize that -Wall is explicitly asking GCC to go over-the-top with warnings, but I assume there's a reason for all of them. So, how could the order of initializing member variables matter?

like image 713
Brendan Long Avatar asked Aug 31 '12 21:08

Brendan Long


People also ask

Why is it important to always initialize variables when you declare them?

Initializing a variable as Telastyn pointed out can prevent bugs. If the variable is a reference type, initializing it can prevent null reference errors down the line. A variable of any type that has a non null default will take up some memory to store the default value.

What is the correct way of initializing the variable?

Generally, all variables should be explicitly initialized in their declaration. The descriptive comment is optional. In most cases, variable names are descriptive enough to indicate the use of the variable. However, provide a comment if further description is appropriate or if an initial value is unusual.

Does order of initializer list matter?

The order of the initializer list does NOT matter. The declaration of your members in the class header defines the initialization order. This is by design and required as you could have multiple ctors having totally different init list orders.

Should member variables be initialized?

You should always initialize native variables, especially if they are class member variables. Class variables, on the other hand, should have a constructor defined that will initialize its state properly, so you do not always have to initialize them.


5 Answers

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.

like image 65
Mark B Avatar answered Oct 05 '22 11:10

Mark B


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

The members will be initialized in the same order they are declared, whether you want it or not. The warning is telling you that the order you are asking for differs from the actual order of execution of initialization.

like image 35
David Rodríguez - dribeas Avatar answered Oct 05 '22 10:10

David Rodríguez - dribeas


You shouldn't because it decreases readability and is potentially misleading.

If you did:

Test() : b(1), a(b) {}

it would appear that b then a were both set to 1, whereas actually the uninitialized value of b is used to initialize a before b is initialized to 1.

like image 40
CB Bailey Avatar answered Oct 05 '22 09:10

CB Bailey


Actually the compiler always initializes the variables in the order of declaration, even if you write the initializers in a different order. Therefore if you don't write the initializations in the order of declaration, the order of your initializers does not fit the order of initialization, which may lead to subtle bugs if the initialisations depend on each other.

For example, consider the code

Test(): b(42), a(b) {}

This is a bug because a is initialized before b, but it looks OK. If you write it in the order of declaration (which is the order of initialization), the bug gets obvious:

Test(): a(b), b(42) {}

Note that the bug can also be subtler than that; for example imagine a and b are class types which output something in their constructor; then with the "incorrect" order you'd think that b's output should appear before a's when in reality the reverse will happen. If a's output appearing first will lead to an invalid file, that's also a bug, but there's no way the compiler could notice the problem if the constructors are in another translation unit (apart from the fact that the compiler cannot know if reordering is or is not a bug). Therefore it's reasonable that the compiler just warns about every instance of non-matching order.

like image 31
celtschk Avatar answered Oct 05 '22 09:10

celtschk


I realize that -Wall is explicitly asking GCC to go over-the-top with warnings, but I assume there's a reason for all of them.

-Wall is just a start. Contrary to what the name implies, -Wall does not enable all warnings. There are some warnings that are arguably "over the top", but those are precisely the warnings that -Wall does not enable. I always use -Wall plus others.

As for your complaint, as others have already noted, there is a very good reason for this warning. Just because you specify an order does not mean the compiler will use that order. The order that the compiler must use per the standard is based upon the class definition.

like image 31
David Hammen Avatar answered Oct 05 '22 10:10

David Hammen