C++ - initializing variables in header vs with constructor

C++ConstructorInitialization

C++ Problem Overview


Regarding the following, are there any reasons to do one over the other or are they roughly equivalent?

class Something
{
    int m_a = 0;
};

vs

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

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

C++ Solutions


Solution 1 - C++

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 - C++

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 - C++

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 - C++

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) {}
};

Solution 5 - C++

class Something
{
    int m_a = 0;
};

is equivalent to

class Something
{
    int m_a(0);
};

So, doing

class Something
{
    int m_a;// (0) is moved to the constructor
public:
    Something(): m_a(0){}
};

yields a uniform syntax for initialization that requires or does not require run-time input.

Personally I don't like the first form because it looks like an "declaration then assignment", which is complete misconception.

Solution 6 - C++

If you change the code like what Christian did to make them do the same thing. Now it is a tradeoff between compile-time optimization (which Christian explained completely) and run-time optimization.

class Foo{

public: 
 Vector<double> vec1;
 .
 .
 .
  Vector<double> vecN;
}

Imagine you have to initialize each vector by some predefined doubles. If the program must instantiate many and many objects of this class, it is better to initialize the vectors in the header file to make the user happy by reducing the run-time!

Solution 7 - C++

Even though it's supported, this type of initialization will create bugs that will be pretty hard to track down. It's the type of "aesthetic optimization" that you will regret a couple months down the road.

See the example below:

class_x_1.h:

class X
{
private:
    int x = 10;
public:
     int GetX();
};

class_x_2.h:

class X
{
private:
    int x = 20;
public:
    int GetX();
};

class_x.cpp:

#include "class_x_1.h" // implementation uses the version that initializes x with 10

int X::GetX()
{
    return x;
}

main.cpp:

#include "class_x_2.h" // main includes definition that initializes x with 20

#include <iostream>

int main()
{
    X x;
    std::cout << x.GetX() << std::endl;
    return 0;
}

Output:

20

As expected, it will return 20 because this is the version that initializes x with 20. However, if you go to the implementation of X, you might expected it to be 10.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEvan WardView Question on Stackoverflow
Solution 1 - C++Christian HacklView Answer on Stackoverflow
Solution 2 - C++Mike SeymourView Answer on Stackoverflow
Solution 3 - C++Mark BView Answer on Stackoverflow
Solution 4 - C++Alexey PolonskyView Answer on Stackoverflow
Solution 5 - C++user3528438View Answer on Stackoverflow
Solution 6 - C++hosh0425View Answer on Stackoverflow
Solution 7 - C++See SharperView Answer on Stackoverflow