Why must initializer list order match member declaration order?
Asked Answered
R

4

28

Why does gcc throw a hissy fit if the initializer list order doesn't match variable order in the class?

class myClass
{
public:
   int A;
   int B;
   myClass();
};

myClass::myClass() :
B(1),
A(2)
{}

will result in:

file.h:274: warning: 'myClass::A' will be initialized after
file.h:273: warning:   'int myClass::B
file.cpp:581: warning:   when initialized here

Is there any specific reason why this kind of warning is issued? Are there any risks associated with initializing variables of a class in order different than they are defined within the class?

(note, there is a question which touches the subject, but the answers are pretty much "because it should be so" without giving any rationale as to why it should be ordered, or what's wrong with this being out of order - I'd like to know why such a restriction exists - could someone give an example where it may backfire maybe?)

Rebeckarebeka answered 18/6, 2014 at 12:4 Comment(11)
@ShafikYaghmour: The standard doesn't make up restrictions because such is a caprice of its writers. Each restriction is result of some considerations. So, no, "because the standard says so" is not a sufficient answer, by far. Sure some decisions of the standard may be questionable, or outright wrong - but even these issues and mistakes stem from certain origins.Rebeckarebeka
So maybe your question should be "Why is the order of initialization the order of declaration?" instead of asking about the warning.Atwitter
"Is there any specific reason why this kind of warning is issued?" -One reason is to help you.Conqueror
D&E has a subsection about this topic (12.9), but it only says that the order has to be defined and the programmer must be able to control it - not why the order of declaration has been used instead of the order in the mem-init-list.Atwitter
@Atwitter you only need to add the fact that there's a single class definition and potentially many mem-init-lists.Runion
@dyp: Now that I understand the issue, I'm gonna ask that in a different question :)Rebeckarebeka
@DavidRodríguez-dribeas So what would be the problem with different orders in different ctors?Atwitter
@ShafikYaghmour Rewording this one would also invalidate the answers.Atwitter
@Rebeckarebeka I re-worded the title to better match the body of the question.Locklear
@dyp: the order of destruction is the reverse of the order of construction (a member can depend on another) if you follow the mem-init-list that is impossible to achieve. (I would write an answer, but typing on the phone is painful :))Runion
@juanchopanza: Thanks. And the difference - 'nonduplicate issue' is that while the other asks an advice "how to solve a problem", I'm asking for 'deeper origins': underlying mechanics that lead to this problem.Rebeckarebeka
L
21

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.

Locklear answered 18/6, 2014 at 12:12 Comment(3)
This does not answer the question, because IF it were permitted to specify the initialization [list] in any order, then what you have written here, i.e. B before A, and A depending upon B, would be just fine. Essentially you have only told us that the standard says non-static data member initialization occurs in the order the members were declared, without giving any logic behind that decision.Sop
@DanielGoldfarb The question is not asking why the standard specifies a certain initialization order of non-static data members. It is asking why an implementation issues a warning in a certain situation, and I have answered that question.Locklear
Perhaps I'm reading it wrong. I know the question starts asking about the compiler warning, but there is more to it than that. "Are there any risks ... order different than they are defined ..." And see the "note," at the end of the question which indicates that stating the standard says so doesn't give a rationale for the standard. Your answer does gives a rationale for the warning, and makes a good point; but it seems to me, it does not answer (to quote the note at the end of the question) "why it should be ordered" in the first place. Imho, Shafik Yaghmour's answer is more complete.Sop
K
29

The warning is indicating that regardless of the order you use in the constructor initialization list the standard requires that non-static data members be initialized in the order they were declared. We can see this by going to the draft C++ standard section 12.6.2 Initializing bases and members paragraph 10 which says:

In a non-delegating constructor, initialization proceeds in the following order:

and includes:

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

Why does the standard require this? We can find a rationale for this in paper The Evolution of C++: 1985 to 1989 by Bjarne Stroustrup in section 6 it says:

The initialization takes place in the order of declaration in the class with base classes initialized before members,

[...]

The reason for ignoring the order of initializers is to preserve the usual FIFO ordering of constructor and destructor calls. Allowing two constructors to use different orders of initialization of bases and members would constrain implementations to use more dynamic and more expensive strategies

Knighthead answered 18/6, 2014 at 14:15 Comment(0)
L
21

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.

Locklear answered 18/6, 2014 at 12:12 Comment(3)
This does not answer the question, because IF it were permitted to specify the initialization [list] in any order, then what you have written here, i.e. B before A, and A depending upon B, would be just fine. Essentially you have only told us that the standard says non-static data member initialization occurs in the order the members were declared, without giving any logic behind that decision.Sop
@DanielGoldfarb The question is not asking why the standard specifies a certain initialization order of non-static data members. It is asking why an implementation issues a warning in a certain situation, and I have answered that question.Locklear
Perhaps I'm reading it wrong. I know the question starts asking about the compiler warning, but there is more to it than that. "Are there any risks ... order different than they are defined ..." And see the "note," at the end of the question which indicates that stating the standard says so doesn't give a rationale for the standard. Your answer does gives a rationale for the warning, and makes a good point; but it seems to me, it does not answer (to quote the note at the end of the question) "why it should be ordered" in the first place. Imho, Shafik Yaghmour's answer is more complete.Sop
T
4

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.

So your members will ALWAYS be initialized in the order of declaration.

Teagan answered 18/6, 2014 at 12:10 Comment(7)
This is by design and required => and why is that an issue ? Why is it that each constructor could not initialize the member in the order they please ?Seal
See #4037719. As there are not several dtors the de-initialization must occur in the reversed order of the initialization.Teagan
I do know, I was just probing you in editing your answer to include the justification of "required" in your answer. BTW, this is completely arbitrary; C++ made an explicit choice that the destruction order would always be the reverse of the construction order, and memorizing the construction order was not deemed useful (don't pay for what you don't need + separate compilation model), thus both the construction order and destruction order are fixed. Other alternatives could have been used.Seal
@MatthieuM. I am curious is that just your personal knowledge or is that design documented someplace?Knighthead
@ShafikYaghmour: personal knowledge (reverse engineered in the case of not using a construction order marker). I have not seen this particular design point addressed anywhere, I guess because it was just "obvious" to the designers :)Seal
@MatthieuM. Bjarne basically says the same thing in the document I linked in my answer. Your wording is nicer though.Knighthead
@ShafikYaghmour: Oh! Thanks for digging up the reference. I am in awe that such a "small" feature actually underwent such thought!Seal
A
-4

I think it's just a matter of cleaness. The order of the declaration of class members is defined in the class's header file, while the constructor is defined in the .cpp file.

Suppose that you are going to add another constructor for this class, and only by looking at the .cpp file where you have B(1), A(2), you might mistakenly think that B will be initialized before A and thus write somethings wrong (e.g., B(42), A(B)). The warning is to prevent this from the very beginning.

Archeozoic answered 20/5, 2021 at 19:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.