Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will the initialization list always be processed before the constructor code?

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";
    }
  }
};
like image 817
Frank Avatar asked Apr 07 '09 02:04

Frank


People also ask

What is initialization list in constructor?

Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.

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.

When should a constructor use an initializer?

Initialization lists allow you to choose which constructor is called and what arguments that constructor receives. If you have a reference or a const field, or if one of the classes used does not have a default constructor, you must use an initialization list.

How constructor solve the problem of initialization?

The constructors should be used to initialize member variables of the class because member variables cannot be declared or defined in a single statement. Therefore, constructors are used in initializing data members of a class when an object is created. Below is the C++ program to illustrate the above concept: C++

What is the constructor initializer list in Java?

The constructor initializer list is below: In the above example, one may think the initialization order is m_glass, m_tyres and m_engine. But the order is Engine, Tyres, and Glass.

Is initializer list must if we want to initialize a class?

If class A had both default and parameterized constructors, then Initializer List is not must if we want to initialize “a” using default constructor, but it is must to initialize “a” using parameterized constructor.

What is the Order of initialization in C++?

The constructor initializer list is below: In the above example, one may think the initialization order is m_glass, m_tyres and m_engine. But the order is Engine, Tyres, and Glass. This is because C++ respects the Objects layout in the class template and not the order in the Constructor.

How do you write an initialization list in Java?

The initialization list is written after the name of the constructor starting with the colon followed by the data members that need to be initialized. The initialization list initializes the members without pre initializing them with empty or garbage values (which happens in normal initialization done inside the constructor).


3 Answers

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;
}
like image 162
paxdiablo Avatar answered Oct 09 '22 20:10

paxdiablo


Yes, C++ constructs all the members before calling the constructur code.

like image 22
lothar Avatar answered Oct 09 '22 19:10

lothar


As already answered, initialization lists get completely executed before entering the constructor block. So it is completely safe to use (initialized) members in the constructor body.

You have made a comment in the accepted answer about having to refer to the constructor arguments, but not the member vars inside the constructor block. You don't.

It is possible that you mistook the fact that you should refer to parameters and not to member attributes inside the initialization list. As an example, given a class X that has two members (a_ and b_) of type int, the following constructor may be ill-defined:

 X::X( int a ) : a_( a ), b( a_*2 ) {}

The possible problem here is that the construction of the elements in the initialization list depends on the order of declaration in the class and not the order in which you type the initialization list. If the class were defined as:

class X
{
public:
   X( int a );
private:
   int b_;
   int a_; 
};

Then, regardless of how you type the initialization list in, the fact is that b_( a_*2 ) will be executed before a_ is initialized since the declaration of the members is first b_ and later a_. That will create a bug as your code believes (and probably depends) on b_ being twice the value of a_, and in fact b_ contains garbage. The simplest solution is not refering to the members:

 X::X( int a ) : a_( a ), b( a*2 ) {} // correct regardless of how X is declared

Avoiding this pitfall is the reason why you are suggested not to use member attributes as part of the initialization of other members.

like image 28
David Rodríguez - dribeas Avatar answered Oct 09 '22 20:10

David Rodríguez - dribeas