Will the initialization list always be processed before the constructor code?
In other words, will the following code always print <unknown>
, and the constructed class will have "known" as value for source_
(if the global variable something
is true
)?
class Foo {
std::string source_;
public:
Foo() : source_("<unknown>") {
std::cout << source_ << std::endl;
if(something){
source_ = "known";
}
}
};
Yes, it will, as per C++11: 12.6.2 /10
(same section in C++14
, 15.6.2 /13
in C++17
):
In a non-delegating constructor, initialization proceeds in the following order (my bold):
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).
Finally, the compound-statement of the constructor body is executed.
The main reason for using init-lists is to help the compiler with optimisation. Init-lists for non-basic types (i.e., class objects rather than int
, float
, etc.) can generally be constructed in-place.
If you create the object then assign to it in the constructor, this generally results in the creation and destruction of temporary objects, which is inefficient.
Init-lists can avoid this (if the compiler is up to it, of course but most of them should be).
The following complete program will output 7 but this is for a specific compiler (CygWin g++) so it doesn't guarantee that behaviour any more than the sample in the original question.
However, as per the citation in the first paragraph above, the standard does actually guarantee it.
#include <iostream>
class Foo {
int x;
public:
Foo(): x(7) {
std::cout << x << std::endl;
}
};
int main (void) {
Foo foo;
return 0;
}