Search

Language Selector

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 2.1 -- Fundamental variable definition, initialization, and assignment, 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:

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.

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

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 you 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:

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.

Quiz Time

1) Write a class named RGBA that contains 4 member variables of type uint8_t named m_red, m_green, m_blue, and m_alpha (#include cstdint to access type uint8_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 optionally 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 2.4a -- Fixed-width integers and the unsigned controversy.

Hint: If your print() function isn’t working correctly, make sure you’re casting uint8_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

41 comments to 8.5a — Constructor member initializer lists

  • srividya

    Its a just an awesome example

  • vvidhu1988

    hi i have a question. Let say there is class A and Class B

    here when i create an object to Class A say

    Is the constructor of class A is called and initializes ‘value’ to 0 or before calling Class A’s constructor, whether Calss B’s constructor will be called? since we also have object(bmember) of class type B.

    Please explain when class B’s constructor will be called.

    Whether in the above code i need to initialize ‘bMember’ of class type B in the Class A’s constructor?? since bMember is also a member in class A. I don’t think it is a proper implementation. Can anyone explain?

    • Nikhil Singhal

      Hi,

      The Ans is Very Simple……

      B constructor first called, because first declaration part is done then A’s Constructor is called, so here B’s object is created first.
      I think you got the answer
      if have any confusion run the following code in debug mode:

  • MrPlow442

    One question.

    Do i have to use body brackets {}?
    Can’t i just write?
    Something() : m_nValue(0), m_dValue(0.0), m_pnValue(0) ; ?

  • petewguy1234

    Good explanation! Thank you!

  • Abhijeet

    Hi Alex,

    You’ve used

    to initialize the variables. There is also the option of using

    Is there any inherent benefit to using one over the other?

  • Jason

    Hi Alex,

    Greatly enjoying your tutorial and very excited to see it completely updated.  The pages you have recently worked on are truly epic.

    I may have missed it, but why does using an initialization list resolve the issues that require const and reference member fields to be initialized at the time of their declaration?

    Best wishes and thank you!

    • Alex

      > why does using an initialization list resolve the issues that require const and reference member fields to be initialized at the time of their declaration?

      Because the initialization list provides initialization values for the member variables, whereas assigning values to the members in the body of the constructor is considered an assignment (not an initialization, even though the constructor itself is called to initialize the class object). As you’re aware, const variables and references require that they be initialized.

  • chiva

    Hello I am a new one here. I am studying in university now.
    Now let’s me release my questions that I don’t understand.
    I would like to understand well on How to make Array Initialize using with default constructor.
    Please share and explain

    I thank you all in advanced

    • Alex

      Prior to C++11, I don’t think there’s a way to initialize a member array.

      In C++11, you can use uniform initialization:

  • v.kurenkov

    Good Day!
    Your result ain’t right (r=0 g=0 b=0 a=255), there should be r=0 g=127 b=127 a=255

    Thank you, site’s just awesome!

  • Pisces

    Hello and thank you for these excellent tutorials! This must be the best learning site ever.

    Could you elaborate if default values initialize or assign variables? What will happen in this case?:

    Thanks!

    • Jeff

      I’d like to add to this question. In the quiz solution, if I understand correctly, it seems the user can also safely instantiate "teal" with

      since all members have default values, is that correct?

      • Alex

        would call the default constructor, which would assign m_red, m_green, and m_blue the value 0. This would be the color black, not teal.

    • Alex

      Initialize. However, if your constructor has an initializer list that gets executed, those will take precedence.

      So, in your example case, assuming your Something() default constructor is called, your Something object will end up with values 0, 0.0, and 0 respectively.

  • Nicolas

    Dear Alex,

    First of all, thank you so much for your tutorials, they have helped me a lot! The new updates also help a lot. The quizzes are a great learning tool.

    I am using a library called GDAL (I already installed it properly and tested it). Now I am trying to create some classes that use some other classes from GDAL. I first created the LC_Raster and it worked fine. Then I created the LC_Product and I get this error: "error C2512: ‘LC_Raster::LC_Raster’ : no appropriate default constructor available"

    I would appreciate a lot if you could please give me some insight about the mistake I am making, since I have spent hours trying to find it without success.

    I am using Visual Studio 2010, so I think it does not have C++11 and that is why the initialization of std::vector is weird. In a few days I will have my usual computer back and I would be able to use Visual Studio 2015.

    Here is the code:

    #include “stdafx.h”
    #include
    #include
    #include
    #include
    #include
    #include
    #include “gdal_priv.h”
    #include “gdal_alg.h”
    #include “cpl_conv.h”
    #include “cpl_string.h”
    #include
    #include
    #include

    class LC_Raster
    {
    private:
    std::string m_parentProductName;
    int m_year;
    std::string m_rasterName;
    GDALDataset* m_SourceRasterDS;

    public:
    LC_Raster(std::string parentProductName, int year): m_parentProductName(parentProductName), m_year(year)
    {
    std::stringstream os;
    os <> yearAsString;

    m_rasterName = “Recon_” + m_parentProductName + “_” + yearAsString + “.tif”;

    m_SourceRasterDS = (GDALDataset*) GDALOpen(m_rasterName.c_str(),GA_ReadOnly);
    }

    void setProductName (std::string name)
    {
    m_parentProductName = name;
    }

    void setRasterYear (int year)
    {
    m_year = year;
    }

    std::string getParentProductName () {return m_parentProductName; }
    int getRasterYear () {return m_year; }
    std::string getFileName () {return m_rasterName; }
    GDALDataset* getRasterGDAL () {return m_SourceRasterDS; }
    };

    class LC_Product
    {
    private:
    std::string m_productName;
    std::vector m_productYears;
    int m_numberOfRasetrs;
    std::vector m_rastersOfProduct;

    public:

    LC_Product(std::string productName, std::vector productYears): m_productName(productName), m_productYears(productYears)
    {
    m_numberOfRasetrs = productYears.size();
    m_rastersOfProduct.resize(productYears.size());

    for (int iii=0; iii < productYears.size(); iii++)
    {
    m_rastersOfProduct[iii] = LC_Raster(productName,productYears[iii]);
    }

    }

    std::string getProductName () {return m_productName; }
    std::vector getProductYears () {return m_productYears; }
    int getNumberOfRasters () {return m_numberOfRasetrs; }

    std::vector calculateNeighboringYears (int yearToPredict, int deltaT)
    {
    std::vector neighborYears;
    int numberOfNeighboringYears = neighborYears.size(); //This is the same as 0

    for (int iii=0; iii = (yearToPredict-deltaT)) && (m_productYears[iii] <= (yearToPredict+deltaT)))
    {
    numberOfNeighboringYears += 1;
    neighborYears.resize(numberOfNeighboringYears);
    neighborYears[numberOfNeighboringYears-1] = m_productYears[iii];
    }
    }

    return neighborYears;
    }
    };

    int _tmain(int argc, _TCHAR* argv[])
    {
    GDALAllRegister();

    //Array with the name of the products
    std::array productNames = {“BC”,”Hist”,”LF”,”MODIS”,”NLCD”,”NLCD92″};

    //Vectors with the year of eahc product
    std::vector yearsBC;
    for (int yearBC = 1938; yearBC <= 2005; yearBC++)
    {
    yearsBC.push_back(yearBC);
    }
    std::vector yearsHist (1,1977);
    int arrayYearsLF[] = {2001,2008,2010,2012};
    std::vector yearsLF (arrayYearsLF, arrayYearsLF + sizeof(arrayYearsLF) / sizeof(int) );
    std::vector yearsMODIS;
    for (int yearMODIS = 2001; yearMODIS <= 2012; yearMODIS++)
    {
    yearsMODIS.push_back(yearMODIS);
    }
    int arrayYearsNLCD[] = {2001,2006,2011};
    std::vector yearsNLCD (arrayYearsNLCD, arrayYearsNLCD + sizeof(arrayYearsNLCD) / sizeof(int) );
    std::vector yearsNLCD92 (1,1992);

    LC_Product NLCD(productNames[4], yearsNLCD);

    LC_Raster rasterTrial(“NLCD”,2001);

    std::cout << rasterTrial.getFileName() <GetGeoTransform(GeoTransform);

    for (int iii=0; iii < 6; iii++)
    {
    std::cout << GeoTransform[iii] << "n";
    }

    return 0;
    }

    I apologize, I could not figure how to format the code.

    Thank you so much for your attention and time.

    • Nicolas

      Here is the code in the appropriate format, I apologize again.

      • Nicolas

        I got the code to build and work by creating a default constructor for LC_Raster and a default constructor for LC_Product. However, I don’t understand why that is necessary since I never call the default constructors in main.

    • Alex

      Taking a quick look at this, I’m not sure why you’d be getting an error about not having an appropriate default constructor. As far as I can see, in both places where you’re declaring an object of type LC_Raster, you’re doing so with parameters. What line of code is it complaining about?

      • Nicolas

        Dear Alex,

        Thank you for your help and time. I found the issue. In the constructor of LC_Product I have a std::vector m_rastersOfProduct containing LC_Raster variables. Te vector is resized, and as soon as it is resized, it tries to call the default constructor of LC_raster, which does not exist. Thus, the solution is to not resize the vector and instead, push_back the elements, or to create a default constructor for LC_raster.

  • nick

    [code]
    #include <iostream>
    #include <cstdint>
    using namespace std;
    class RGBA {
    public:
    RGBA (uint8_t red,uint8_t green,uint8_t blue)
    :m_red(0),m_green(0),m_blue(0),m_alfa(255){
    m_red=red;
    m_green=green;
    m_blue=blue;
    }
    void print() {cout<<"R : "<<(int)m_red<<"\nG : "<<(int)m_green<<"\nB : "<<(int)m_blue<<"\nA : "<<(int)m_alfa;
    };
    private:
    uint8_t
    m_red,
    m_green,
    m_blue,
    m_alfa;
    };
    int main(){
    RGBA o(0,127,127);
    o.print();
    return 0;
    }
    [/cdoe]

  • cei

    Hi. I am a bit confused: is it better to use member initializer lists or directly assigning a default value to member variables via non-static member initialization?
    Up until now I have always used the former, but now it seems to me more convenient to use the latter, as it makes a class easier to understand (no need to jump to the member initializer list to see what the initial values of the class’ members are).

    • Alex

      Non-static member initialization is preferred, if you have a compiler that supports it, for precisely the reason you’ve identified.

      You can still use member initialization lists for any values the constructor needs to change from the default value.

  • Lokesh

    At the beginning of this lesson, the names of variables used in code and those used to explain the code below it are different.
    "When the class’s constructor is executed, m_nValue, m_dValue, and m_chValue are created." It should be:
    "When the class’s constructor is executed, m_value1, m_value2, and m_value3 are created."

  • Lokesh

    In section "Initializing array members with member initializer lists", you said that prior to C++11, you could only zero the elements using a blank list for initializing the members of an array. Following is the example code provided:

    However, since the array elements are of type <const int>, we cannot assign values to them once we have initialized them(in this case with zero for all elements). So, my question is how did we initialize elements of an integer array of type <const int> prior to C++11 when an instance of a class is created ?

  • Lokesh

    I think you should not use the words "explicit assignment" as there is no such thing as implicit assignment. It is more confusing since we use the terms implicit and explicit when referring to initialization (uniform initialization is also implicit which happens to work for all data types). You should say just "assignment". I am referring to the sentence:
    "Note that we no longer need to do the explicit assignments in the constructor body, …"

  • SJ

    Hi Alex,

    I am a bit confused with the solution to the quiz question. I am not sure what the purpose of instantiating the member variables to 0,0,0,255 was, as in here:

    because we immediately go ahead to include a constructor, requiring the user to include the RGB color values upon instantiating of an RGBA object. So something like

    gives me an error and not the default color object containing 0,0,0,255.

    So I’m just wondering why we defaulted these values when we declared the member variables?

    *** Edit: ***
    I see you touch upon exactly this in the next topic. But I believe the solution here should still be updated?

    • Alex

      I’ve removed the non-static member initializers since we haven’t covered those yet.

      • SJ

        Was I correct in saying that

        would not compile? There was no constructor for it that took no arguments and there was one that required the RGB arguments.

        Also the solution still says to default the values to 0,0,0,255 so I think either the question or the solution should be altered 😛

  • Irene

    How can the constructor have 4 values while

    has only three? My compiler takes that as an error.

    • Alex

      The constructor has default values for all parameters:

      So any parameter that is not provided when an RGBA object is created will use the defaulted value.

      RGBA teal(0, 127, 127) is the equivalent of RGBA teal(0, 127, 127, 255) with the defaulted parameter.

Leave a Comment

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

  

  

  

14 + six =