Search

8.5a — Constructor member initializer lists

In the previous lesson, for simplicity, we initialized our class member data in the constructor using the assignment operator. For example:

When the class’s constructor is executed, m_value1, m_value2, and m_value3 are created. Then the body of the constructor is run, where the member data variables are assigned values. This is similar to the flow of the following code in non-object-oriented C++:

While this is valid within the syntax of the C++ language, it does not exhibit good style (and may be less efficient than initialization).

However, as you have learned in previous lessons, some types of data (e.g. const and reference variables) must be initialized on the line they are declared. Consider the following example:

This produces code similar to the following:

Assigning values to const or reference member variables in the body of the constructor is clearly not sufficient in some cases.

Member initializer lists

To solve this problem, C++ provides a method for initializing class member variables (rather than assigning values to them after they are created) via a member initializer list (often called a “member initialization list”). Do not confuse these with the similarly named initializer list that we can use to assign values to arrays.

In lesson 1.4 -- Variable assignment and initialization, you learned that you could initialize variables in three ways: copy, direct, and via uniform initialization (C++11 only).

Using an initialization list is almost identical to doing direct initialization (or uniform initialization in C++11).

This is something that is best learned by example. Revisiting our code that does assignments in the constructor body:

Now let’s write the same code using an initialization list:

This prints:

Something(1, 2.2, c)

The member initializer list is inserted after the constructor parameters. It begins with a colon (:), and then lists each variable to initialize along with the value for that variable separated by a comma.

Note that we no longer need to do the assignments in the constructor body, since the initializer list replaces that functionality. Also note that the initializer list does not end in a semicolon.

Of course, constructors are more useful when we allow the caller to pass in the initialization values:

This prints:

Something(1, 2.2, c)

Note that you can use default parameters to provide a default value in case the user didn’t pass one in.

Here’s an example of a class that has a const member variable:

This works because we’re allowed to initialize const variables (but not assign to them!).

Rule: Use member initializer lists to initialize your class member variables instead of assignment.

Uniform initialization in C++11

In C++11, instead of direct initialization, uniform initialization can be used:

We strongly encourage you to begin using this new syntax (even if you aren’t using const or reference member variables) as initialization lists are required when doing composition and inheritance (subjects we will be covering shortly).

Rule: Favor uniform initialization over direct initialization if your compiler is C++11 compatible

Initializing array members with member initializer lists

Consider a class with an array member:

Prior to C++11, you can only zero an array member via a member initialization list:

However, in C++11, you can fully initialize a member array using uniform initialization:

Initializing member variables that are classes

A member initialization list can also be used to initialize members that are classes.

This prints:

A 4
B 5

When variable b is constructed, the B(int) constructor is called with value 5. Before the body of the constructor executes, m_a is initialized, calling the A(int) constructor with value 4. This prints “A 4”. Then control returns back to the B constructor, and the body of the B constructor executes, printing “B 5”.

Formatting your initializer lists

C++ gives you a lot of flexibility in how to format your initializer lists, and it’s really up to you how you’d like to proceed. But here are some recommendations:

If the initializer list fits on the same line as the function name, then it’s fine to put everything on one line:

If the initializer list doesn’t fit on the same line as the function name, then it should go indented on the next line.

If all of the initializers don’t fit on a single line (or the initializers are non-trivial), then you can space them out, one per line:

Initializer list order

Perhaps surprisingly, variables in the initializer list are not initialized in the order that they are specified in the initializer list. Instead, they are initialized in the order in which they are declared in the class.

For best results, the following recommendations should be observed:
1) Don’t initialize member variables in such a way that they are dependent upon other member variables being initialized first (in other words, ensure your member variables will properly initialize even if the initialization ordering is different).
2) Initialize variables in the initializer list in the same order in which they are declared in your class. This isn’t strictly required so long as the prior recommendation has been followed, but your compiler may give you a warning if you don’t do so and you have all warnings turned on.

Summary

Member initializer lists allow us to initialize our members rather than assign values to them. This is the only way to initialize members that require values upon initialization, such as const or reference members, and it can be more performant than assigning values in the body of the constructor. Member initializer lists work both with fundamental types and members that are classes themselves.

Quiz Time

1) Write a class named RGBA that contains 4 member variables of type std::uint_fast8_t named m_red, m_green, m_blue, and m_alpha (#include cstdint to access type std::uint_fast8_t). Assign default values of 0 to m_red, m_green, and m_blue, and 255 to m_alpha. Create a constructor that uses a member initializer list that allows the user to initialize values for m_red, m_blue, m_green, and m_alpha. Include a print() function that outputs the value of the member variables.

If you need a reminder about how to use the fixed width integers, please review lesson 4.6 -- Fixed-width integers and size_t.

Hint: If your print() function isn’t working correctly, make sure you’re casting uint_fast8_t to an int.

The following code should run:

and produce the result:

r=0 g=127 b=127 a=255

Show Solution

8.5b -- Non-static member initialization
Index
8.5 -- Constructors

218 comments to 8.5a — Constructor member initializer lists

  • Parsa

    Why do the member variables need to be casted to an int? (quiz)

  • x-ray

    As Winchester already mentioned, the following statement is not correct (anymore?): "In lesson 4.1 -- Introduction to fundamental data types, you learned that you could initialize variables in three ways: copy, direct, and via uniform initialization (C++11 only)." This is now in 1.4 — Variable assignment and initialization.

  • Samira Ferdi

    Hi, Alex and Nascardriver!

    > Don’t initialize member variables in such a way that they are dependent upon other member variables being initialized first (in other words, ensure your member variables will properly initialize even if the initialization ordering is different).

    What's mean of  " ensure your member variables will properly initialize even if the initialization ordering is different"? In fundamental type I understand the meaning, but in class member variable?

    • Line 24 causes undefined behavior. Members are initialized in the order of their declaration. The order in the member initializer list is irrelevant. `m_arrData` was initialized first. When it was initialized, `m_iLength` was still `0`.

      • Samira Ferdi

        Thank you, Nascardriver!
        I understand the idea of members are initialized (in the initializer list) in the order of their declaration.

        But, the statement "ensure your member variables will properly initialize even if the initialization ordering is different" that Alex said in my mind is like our initialization has nothing to do with the ordering of the declaration of the variables. In non-class variable I understand the meaning of that statement (because the initialization has nothing to do with declaration ordering). So, it makes me think how to initialize class member variables that independent with members declaration order. So, if this thing that I should do, how can I do it?

        • You should write your code such that the order of declaration doesn't matter. The code I wrote above shouldn't use `m_iLength` to initialize, even if line 4 and 5 were swapped. The constructor should be

          That way the order of declaration can't break the initialization.

  • Alexsander

    Hi!

    First of all, I would like to say that I'm pretty addicted to this site. C++ is awesome!
    I've noted that, in Summary, it is written that the initializer list is the only way to initialize member variables thats require values upon initialization. I think that there's one more way to do that: initilializing the member variables at the place where they are declared, like this example:

    class Box {
      int items = 3;
    public:
      Box () {}
    };

    Please correct me if it's wrong.

  • vegan cat

    Hi! I tried to put the class in a header file and run into problems - there is an error in my constructor definition. The compiler complains that it wants a semicolon instead of a comma after "int8 red = 0" (i used my own typedef instead of the one requested thinking it would solve the problem - it didn't). Also, I get the feeling that including iostream in a header file is bad and could screw up my program - am I even allowed to do this? How would one define a class like that in a header file? Does it even make sense?

    • RGBA is a preprocessor definition (Line 2), you can't re-use it. Change the name of the header guard or class to fix the problem.

      > including iostream in a header
      Include as few other headers in a header as possible.
      Move the definitions of `RGBA::RGBA` and `RGBA::print` into a source file, then you don't need <iostream> in the header anymore.

      > am I even allowed to do this?
      Yes, but it should be avoided as it can lead to circular includes, name conflicts, and slower compilation.

      > Does it even make sense?
      Yes, you should put classes into headers.

  • Jan Perme

    Anyone has a clue, why this initialization of pointers in Facade class works ? Thanks.

  • Torraturd

    Hi, I'm just wondering if it is an issue if i declare my variables like this:

    as opposed to this:

    because I don't see other people doing this often, and I was wondering if there is something wrong with declaring variables like that

  • satheesh_k

    Hi I want to create a class where it has two class members, one is array size and another is array itself. I want to ask user to input array size.
    How can i initialise array in class constructor based  on user input?

    but i am getting compilation errors. Please suggest a way to do this.

    • - `numArray` has to be a member of `Stack`.
      - Initialize your variable with brace initializers.
      - Missing printed trailing line feed.
      - Use ++prefix unless you need postfix++.

      Dynamically allocate the array in the constructor. Loop until `sample_stack.arraySize` in `main`, extracting into `sampleStack.numArray[i]` in every cycle.

      • Satheesh K

        Thank you, I have done the following but not sure this is what you have said. But it is working fine. if I am missing some thing please let me know

  • Nguyen

    Hello,

    I have two questions in line 14 and line 17.  Could you please explain?

    • Nguyen

      Hello,

      Please ignore my questions.  I could answer myself.  I modified the same program to make sure I really understand.  
      Here is my updated version.

      Thanks, Have a great day.

  • McDidda

    Consider following snippet of code

    So I think here first initialization of m_value will takes place (am I correct) and then  body of constructor will get executed.
    My question is: can I use m_value in the body of "Something()"constructor?

  • McDidda

    hi Alex,
         I'm learning initializatioh list for class member initialization. I wrote the following code:

    My problem is :
    It gets compiled. I guess it means there is no problem with the code. Now although  m_1 is "const int"  still user could change it's value!!!.

  • Mario Drouga

    Why is this not allowed:

  • Dimitri

    1) If uniform initialization is used, which option is preferable?

    a)

    b)

    2) Is the libraries writing order important?

    or

    • Dimitri

      1) a

      2) sometimes yes (sorry, I had to google first:))

    • 1) a with an overloaded constructor so you can still construct an @RGBA with 3 arguments.
      2) Unfortunately sometimes yes. As long as a header doesn't want to be included in a specific place, sorting your includes alphabetically can help managing your includes.
      C++20 will add modules, which should be independent of their import order.

  • Winchester

    What is the real difference between direct and uniform initialization, performance-wise?

    Something(): m_value(5){}
    vs.
    Something(): m_value{5}{}

    BTW, lesson 4.1 been recently updated. So the following statements don't apply any more.

    "In lesson 4.1 -- Introduction to fundamental data types, you learned that you could initialize variables in three ways: copy, direct, and via uniform initialization (C++11 only)."

    • There is no performance difference. Uniform initialization works with lists, prevents narrowing casts, and can default-initialize. Direct initialization can't do these things.

      There used to be a performance difference between copy- and direct/uniform-initialization. If I understood correctly, this is no longer the case.

      • Atas

        Dear nascardriver, what is your opinion on this: https://medium.com/@barryrevzin/uniform-initialization-isnt-82533d3b9c11
        Is it a good advice to never use uniform initialization unless you're initializing an aggregate?

        • I don't agree. Renouncing the benefits of brace initialization, because you don't want to think about the type you're initializing isn't worth it in my opinion.
          I go by "If the type you're initializing might have a list constructor and you don't want to use it, use direct initialization.". This rule has served me good so far and isn't hard to enforce.

  • Hello, I'm confused as to why the compiler doesn't give me an error when I don't
    use uniform initialization for MainWindow &m_mainWindow;
    But does for MainWindow &m_mainWindow{}; and that I have to make it const.

    • Empty initializers lists create a temporary object which is used to initialize the variable.

      Tries to instantiate a @MainWindow and use it to initialize @m_mainWindow. The temporary is an r-value, so you're not allowed to modify it, but referencing it would mean that you can modify it.
      You can think of it like a reference to a literal.

      By not initializing @m_mainWindow at its declaration, you're forced to initialize it in the constructor.

  • J

    Hello!

    Is it acceptable that my type alias only exists in the scope of the RGBA class or is it considered better practice to make it global via a head file?

    • Alex

      It's always better to put things in a smaller scope if you can, so putting your type alias in the scope of the class is better than in the global scope.

  • Envy

    In the segment: Initializing array members with member initializer lists

    The second code snippet reads the following:

    If I'm not completely mistaken the comment on line 9 doesn't make sense.
    In line 4 m_array is declared as const which means any assignments to that array will produce a compiler error.
    Or am I missing something?

  • Barne

    My solution:

    The alias makes it much more readable imo.
    The only eyesore is the static cast, is there a way of just type deffing or using an alias for that or would I need a function like intCast(m_green) that just returns a static cast?

    • * Line 32: Initialize your variables with brace initializers. You used direct initialization.
      * Line 8, 9, 10, 11: Initialize your variables with brace initializers.

      > intCast(m_green) that just returns a static cast?
      That wouldn't make the situation any better, would it? All it does is remove the template argument.

      Arithmetic on types smaller than int promotes those types to an int. You could use the unary operator+.

      But the cast is easier to understand.

  • Max Morgan

    Error: no matching function for call to 'RGBA::RGBA (int, int int)'

    • * Line 14, 20, 35: Initialize your variables with brace initializers. You used direct initialization.
      * Line 8, 9, 10, 11, 32: Initialize your variables with brace initializers.
      * Line 19, 25: Limit your lines to 80 characters in length for better readability on small displays.

      There is no constructor that accepts 3 ints.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]