Search

8.5b — Non-static member initialization

When writing a class that has multiple constructors (which is most of them), having to specify default values for all members in each constructor results in redundant code. If you update the default value for a member, you need to touch each constructor.

Starting with C++11, it’s possible to give normal class member variables (those that don’t use the static keyword) a default initialization value directly:

This program produces the result:

length: 1.0, width: 1.0

Non-static member initialization (also called in-class member initializers) provides default values for your member variables that your constructors will use if the constructors do not provide initialization values for the members themselves (via the member initialization list).

However, note that constructors still determine what kind of objects may be created. Consider the following case:

Even though we’ve provided default values for all members, no default constructor has been provided, so we are unable to create Rectangle objects with no parameters.

If a default initialization value is provided and the constructor initializes the member via the member initializer list, the member initializer list will take precedence. The following example shows this:

This prints:

length: 2.0, width: 3.0

Note that initializing members using non-static member initialization requires using either an equals sign, or a brace (uniform) initializer -- the direct initialization form doesn’t work here.

Rule: Favor use of non-static member initialization to give default values for your member variables.

Quiz time

1) Update the following program to use non-static member initialization and member initializer lists.

This program should produce the result:

color: black, radius: 10
color: blue, radius: 10
color: black, radius: 20
color: blue, radius: 20

Show Solution

2) Why do we need to declare an empty default constructor in the program above, since all members are initialized via non-static member initialization?

Show Solution

8.6 -- Overlapping and delegating constructors
Index
8.5a -- Constructor member initializer lists

51 comments to 8.5b — Non-static member initialization

  • AMG

    Hey Alex,
    I would suggest before "Starting with C++11, it’s possible to give non-static class member variables a default initialization…", to say few words about static class members and non-static class members. Otherwise, it is a sudden transition to initialization of something, which has not beed referenced before, or provide links to them. Great, great tutorial.

    • Alex

      This is always a hard thing. If I talk too much about static members here, people will start asking questions about them here, and how they differ. I’ve updated the article to better define what a non-static member is, without talking any more about what a static member is. Thanks for the suggestion.

  • Nikita

    Hi Alex! In the previous lesson I think you said to prefer uniform initialization over direct or copy. So now, when I was doing the quiz, the following code caused an error.

    I am using Visual Studio 2013, and usually, uniform initialization works fine, but could it be that C++ compiler is not suitable or I have some misunderstanding.
    Thanks for your tutorials, very helpful!

  • Dani

    Ball(const std::string &color):  
            m_color(color)
        {
        }
             why we use reference (&color) ? i think it can handle with "color"…Thnks

    • Alex

      Class and struct parameters should be passed by reference, not by value, to avoid making an expensive and unnecessary copy.

      • Dani

        Thank you very much Alex

      • :|

        Its good to include ALL the parameters by reference? like &radius? or only things bigger than strings?

        Also, why is the string in the parameters a constant? if i delete the const the program wont work but i dont understand why (in the quiz problem).

        • Alex

          No, typically only class objects are passed by (const) reference, or parameters where the function needs to change the value of the argument.

          The string parameter is a const reference so it can take r-value arguments. Const references can reference both l-values and r-values, const or not. Non-const references can only take non-const l-value parameters, which makes them somewhat limited.

          • Jeremiah

            I apologize but I am also confused by this. The argument in this example is a string literal. I don’t understand how a string literal can be passed by reference even if it is const. Does this mean a string literal has an address in memory, if not, how can it be referenced?

            Thank you.

            • Alex

              Yes, string literals have an address in memory. Normal references are only allowed to bind to l-values (objects which persist beyond the scope of a single expression). But const references can bind to r-values, which only exist temporarily. String literals are r-values.

  • Le Thu Ha

    Hi Alex,
    Why they are called non-static member?

  • CodeBee

    We know that in class declaration, the memory is not created.It is only created when a object is made.But in non-static member initialization, when the compiler will compile the line

    will it not try to allocate a memory for the variable and assign the value to it?
    Because it is similar to the line:

    . In this case, memory for x is created at this point.

    • Alex

      > But in non-static member initialization, when the compiler will compile the line

      The compiler compiles the line when you compile your program. 🙂 You’re really asking how this works.

      When you declare a variable of an object, memory is allocated for the object at that point, and the constructor is called to initialize the object. Any members specified as part of the member initialization list are initialized with the values specified as part of the member initialization list (this supersedes any non-static member initialization). If a member is not specified on the member initialization list, but a non-static member initializer is provided, that will be used instead. If a member is not specified on the member initialization list and no non-static member initializer is provided, the will be initialized using the default constructor (for objects) or not at all (for fundamental variables).

  • Tyler

    In the quiz section why does color use the address operator, but the radius doesn’t?

    Thank you.

    • Alex

      The ampersand in this context isn’t the address operator, but used to indicate that the std::string is being passed by reference.

      std::string is a class, and you should always pass classes by reference (or const reference) so they aren’t copied. Fundamental types are fine to pass by value.

  • Sivasankar

    Hi Alex, Thanks for your lessons.
    Just to confirm, the below statement
    "Note that initializing members using non-static member initialization requires using either an equals sign, or a brace (uniform) initializer -- the direct initialization form doesn’t work here" means the way of initializing m_breadth in following code is wrong. Am I correct?

    • Alex

      Correct. You could have validated your statement yourself by seeing if it compiled. 🙂

      • Zangin

        Thanks for your valuable tutorials. They are very pedagogical.
        Is it still like that in C++14?
        I wrote the code like that, and it works.
        #include "stdafx.h"
        #include <iostream>
        class Rectangle
        {
        private:
            double m_length{ 1.0 };
            double m_width{ 1.0 };

        public:

            Rectangle(double length, double width)
                : m_length(length), m_width(width)
            {
                // m_length and m_width are initialized by the constructor (the default values aren’t used)
            }

            void print()
            {
                std::cout << "length: " << m_length << ", width: " << m_width << ‘\n’;
            }

        };

        int main()
        {
            Rectangle x(2.0, 3.0);
            x.print();

            return 0;
        }

        • Alex

          Yes, it’s still like that. The poster was asking about non-static member initialization syntax, not member initializer list syntax.

          When directly initializing a non-static member, you can only use equals or uniform initialization. For member initialization, you can use direct initialization or uniform initialization.

  • Yan

    Hi, Alex. Thanks for the awesome tutorials.
    I have a strange situation. I did the task in the quiz just like in your solution but my Visual Studio (2013 update 4) doesn’t run it. It throws "Error C2797: List initialization inside member initializer list or non-static data member initializer is not implemented."
    It complains about this line:

    What can be done to fix this? Thanks.

    • Alex

      So it looks like Visual Studio 2013 doesn’t support the brace initialization form for non-static member initialization. You can either switch to Visual Studio 2015, or change your initializers to use an equals sign instead (which seems a bit easier, doesn’t it?). I’ve updated the quiz to use equals signs for now.

  • Ben

    For our Square class, don’t we only need one input parameter because the definition of a square tells us that all sides have the same length? And therefore it should also be impossible to set our Square’s width and length to different values when we construct it. For example:

    Here’s a possible fix?

    That our you can just change the class name to Rectangle.

    Great stuff so far on the C++ tutorial! I am really enjoying it and I feel like I’ve learned a ton.

  • Darren

    This is somewhat pedantic but in the example code segments above, the non-static member initialisation is done by assignment initialisation. However, as this is a C++11 thing shouldn’t it be done by uniform initialisation, as per the recommendation in the previous chapter?

  • Nyap

    What do you mean by non-static

  • Shiva

    Alex,

    Please correct: "…if the constructors do not provide an initialisation values…"

    🙂

  • P

    Hi, thank you for the tutorial!
    Is it customary to indent the default constructor?

  • Joshua Richards

    Would this solution be better since it produces the same output, has only two constructors that can handle all for Ball objects, and demonstrates all of the concepts we have learned in this lesson?

    #include <iostream>
    #include <string>

    class Ball
    {
    private:
        std::string m_color{"Black"};
        double m_radius{10.00};

    public:
        Ball(const std::string &color="Black", double radius=10.0)
        : m_color{color}, m_radius{radius}
        {
        }
        Ball(double radius)
        : m_radius{radius}
        {
        }
        void print()
        {
            std::cout << "Color: " << m_color
            << ", Radius: " << m_radius << ‘\n’;
        }
    };

    int main()
    {
        Ball def;
        def.print();
        
        Ball blue("Blue");
        blue.print();
        
        Ball twenty(20.00);
        twenty.print();
        
        Ball blueTwenty("Blue", 20.00);
        blueTwenty.print();
        
        return 0;
    }

  • Bassam

    Hi! Alex. Thank you for this very useful explanation. I think you should use double instead of int in the constructor parameters for the second and third example.

  • Lokesh

    I think the following program demonstrates all the rules about default constructors. I found the concept a bit twisty. I think you should use this particular example for quiz question no.1 as it serves as a summary(it just adds one or two concepts to what already exists in the question).

    • Alex

      I’ve updated the quiz question with some of your suggestions. Thanks!

      • Lokesh

        I kindly disagree with:

        I think we need a default constructor(we have to define our own) because although the private member variables have default values, these are non-static. So, we cannot instantiate an object without any values(no parameters) that will automatically take on the default values provided for the member variables. So, although we have used non-static member initialization, we need to define an "empty" constructor in order for us to instantiate an object with no parameters. As I have said earlier, we need a default constructor as so:

        Secondly, you cannot use "default" as an identifier(in quiz-1 solution) because it is a keyword in C++.

        • Alex

          Agreed with your assessment. Not sure how I messed that up. The article has been fixed.

          • Keanu

            Hi Alex. I was reading the above comment thread and think I may be misunderstanding something. Lokesh says "we cannot instantiate an object without any values(no parameters) that will automatically take on the default values provided for the member variables" when using non-static member initialization without a user-defined default constructor. I was confused by why this would be so when I saw you agree with the comment, I decided to run the provided code without a user-defined default constructor using a print function called by main().
            This is the code:

            This prints: colour:black radius:10
            I compiled the code in visual studio 2015 and an online compiler with the "stdafx" removed - both worked fine and produced the expected outcome. I feel like there’s some sort of blind spot here for me, have I misunderstood Lokesh’s comment?

            • Alex

              Two things to remember:
              1) Constructors determine what type of objects you can create
              2) C++ will create a default public constructor for you if you’ve provided no constructors.

              The reason your code works is because of the latter -- you don’t have any constructors, so C++ is creating one for you, and using it to create ball.

              If you had another (non-default) constructor, this wouldn’t work, even though you’ve defaulted your values. By explicitly defining an empty default constructor, we’re ensuring we can create objects of type Ball with no parameters regardless of whether other constructors exist or not.

            • Keanu

              Ah, I see what happened. For some reason I thought the bit of code which Lokesh says he "kindly disagrees with" was in isolation; I didn’t realize that it was part of a larger segment of code that included non-default constructors. Makes total sense now. Thanks for the speedy response Alex, given you’ve been running this site for around 9 years, it’s extraordinary you still maintain it so well and respond to questions within days.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter