C++ - initializing variables in header vs with constructor

Solution 1:

The two code snippets you posted are not quite equal.

class Something
{
    int m_a = 0;
};

Here you specify the value with which to initialise, i.e. 0, at compile time.

class Something
{
    int m_a;
    Something(int p_a);
};

Something::Something(int p_a):m_a(p_a){ ... };

And here you do it at run time (or possibly at run time), with the value p_a not known until the constructor is called.

The following piece of code comes closer to your first example:

class Something
{
    int m_a;
    Something();
};

Something::Something() : m_a(0) { /* ... */ };

What you have to consider here is that in the first case, the value appears directly in the class definition. This may create an unnecessary dependency. What happens if you need to change your 0 to 1 later on? Exposing the value directly in the class definition (and thus, usually, in a header file) may cause recompilation of a lot of code in situations where the other form of initialisation would avoid it, because the Something::Something() : m_a(0) part will be neatly encapsulated in a source file and not appear in a header file:

// Something.h - stable header file, never changed
class Something
{
    int m_a;
    Something();
};

// Something.cpp - can change easily
Something::Something() : m_a(0) { /* ... */ };

Of course, the benefits of in-class initialisation may vastly outweigh this drawback. It depends. You just have to keep it in mind.

Solution 2:

The first form is more convenient if you have more than one constructor (and want them all to initialise the member in the same way), or if you don't otherwise need to write a constructor.

The second is required if the initialiser depends on constructor arguments, or is otherwise too complicated for in-class initialisation; and might be better if the constructor is complicated, to keep all the initialisation in one place. (And it's also needed if you have to support pre-C++11 compilers.)

Solution 3:

The first form is new to C++11 and so at this point isn't terribly well supported, especially if you need to support a variety of older compilers.

Otherwise they should be roughly equivalent when a C++11 compiler is available.

Solution 4:

Elaborating on Christian Hackl's answer.

The first form allows to initialize m_a and have a default c'tor at the same time. Or you can even be explicit in your code and define a constructor with the default keyword:

class Something
{       
    int m_a = 0;

    // explicitly tell the compiler to generate a default c'tor
    Something() = default;
};

With the second form, an auto-generated default c'tor would leave m_a uninitialized, so if you want to initialize to a hard-coded value, you have to write your own default c'tor:

class Something
{
    int m_a;

    // implement your own default c'tor
    Something() : m_a(0) {}
};