31

Please explain how to use member initializer lists. I have a class declared in a .h file and a .cpp file like this:

class Example
{
private:
    int m_top;
    const int m_size;
    /* ... */
public:
    Example(int size, int grow_by = 1) : m_size(5), m_top(-1);
    /* ... */
    ~Example();
};

I'm initializing m_size on object creation because of const. How should I write the constructor? Should I repeat : m_size(5), m_top(-1), or I can omit this step?

Example::Example(int size, int grow_by)
{
    /* ... */
}

or

Example::Example(int size, int grow_by) : m_size(5), m_top(-1)
{
    /* ... some code here */
}
Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Yesman
  • 437
  • 1
  • 4
  • 5
  • 3
    You specify the initialization list when you define the constructor, not when you declare it. – wkl Oct 05 '11 at 17:14

6 Answers6

65

Just to clarify something that came up in some of the other answers...

There is no requirement that the initializer list be in either the source (.cpp) or header (.h) file. In fact, the compiler does not distinguish between the two types of files. The important distinction is between the contructor's declaration and it's definition. The initializer list goes with the definition, not the declaration.

Usually, the declaration is in a header file and the definition is in a source file, however, this is not a requirement of the language (i.e. it will compile). It is not unusual to provide constructor definitions inline in the class declaration when the constructor is empty or short. In that case, an initializer list would go inside the class declaration, which would probably be in a header file.

MyClass.h

class MyClass
{
public:
    MyClass(int value) : m_value(value)
    {}
private:
    int m_value;
};
Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
BHS
  • 1,079
  • 1
  • 6
  • 10
  • Note: some frameworks and languages like Qt's C++ require their classes and structs derived from `QObject` to use their own header for leveraging their `Q_OBJECT` macro to properly take advantage of its potential. – kayleeFrye_onDeck Jul 14 '17 at 00:02
27

This is the initializer list:

Example::Example( int size, int grow_by) : m_size(5), m_top(-1)
{
    /* ... */
}

and it should be done only in the .cpp file.

If you did it in the header like in your example, you would get an error.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
BЈовић
  • 62,405
  • 41
  • 173
  • 273
15

The member initializer list should be a part of the constructor definition in the source file. Write this in the .cpp file:

Example(int size, int grow_by) : m_size(5), m_top(-1)
{
    /* ... */
}

The header file should only have:

Example(int size, int grow_by = 1);

The header file only declares the constructor, the member initializer list is not a part of the declaration.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • I.e. initialiser list only goes into constructor definition. – Cat Plus Plus Oct 05 '11 at 17:15
  • @CatPlusPlus: Oh a bit late just had it edited before your comment :P – Alok Save Oct 05 '11 at 17:15
  • I think the `= 1` default parameter should only be in the header, not the `cpp` file. – Mooing Duck Oct 05 '11 at 17:16
  • @MooingDuck: Correct! Ah err `cntrl + c`, `cntrl + v` Bad habit :P! – Alok Save Oct 05 '11 at 17:18
  • Additionally, data members are initialized in the order they are declared, so it is good practice to order your initializer list in the same way to be consistent. In your example, that would be `: m_top(-1), m_size(5)`. See [Effective C++](http://www.aristeia.com/books.html) by Meyers, Item 4. – David Alber Oct 05 '11 at 17:20
9

Adding to others answers, the one most important thing one should remember about the initializer list is that:

the order of initialization is decided in the order in which the data members are declared, not the the order in which you have initialized the data members using initialization list

Consider your example:

class Example
{
private:
    int m_top;
    const int m_size;
    /* ... */
public:
    Example(int size, int grow_by = 1) : m_size(5), m_top(-1) {}
    /* m_size appears to be initialized with a value first,
     * but m_top is initialized to the value -1 before
     * m_size is initialized to 5. */
    
    /* ... */
    ~Example(){}
};

If one is not aware of the above, it has very serious implications.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Arunmu
  • 6,837
  • 1
  • 24
  • 46
  • 1
    Many compilers will warn about initialization order if it looks like there might be an ambiguity that could cause problems. You should enable such warnings if they are not and pay attention to such warnings. – emsr Oct 05 '11 at 17:27
  • Yes but still worth enough to know what the warning is really about :) – Arunmu Oct 05 '11 at 17:31
1

In C++11 you can use non-static data member initialization. This is especially useful if you have several constructors that need a common value for a member variable.

class Example
{
private:
    int m_top = -1;
    const int m_size = 5;
    ...
public:
    Example ( int size, int grow_by = 1 );
    ...
    ~Example();
};

...

Example::Example( int size, int grow_by )
{
    ... some code here
}

You can override the value in a constructor if you need to.

emsr
  • 15,539
  • 6
  • 49
  • 62
1

You cannot have an initializer list both in the header and the source file. The list should be in whichever file defines your constructor. Also you must include a body when defining the constructor, even if it's empty.

On a side note, you should only specify the default arguments in the function prototype, not in the definition.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
minus
  • 706
  • 5
  • 14