0

I've learned what is an initialization list and how to use it but I still was wondering a thing.

What is the difference, if there is, between initializing variables of the class by using an initialization list or doing it by yourself in the constructor?

E.g.

class MyClass {
public:

    MyClass() : m_classID(-1), m_userdata(0) { 
    }

    int m_classID;
    void *m_userdata;
};

VS

class MyClass {
public:

    MyClass(){
        m_classID = -1;
        m_userdata = 0;
    }

    int m_classID;
    void *m_userdata;
};

Is it just a designing habit which makes code easier to read and write or is there some other specific reason?

Community
  • 1
  • 1
Matteo
  • 7,924
  • 24
  • 84
  • 129

6 Answers6

3

If those variables are fundamental types, and they are not const and not references, then there is no difference.

If your member is a reference or it is const, then you will have to initialize them, and that can only be done through an in initialization list, for the same reason that forbids you creating an uninitialized reference or const variable of a fundamental type:

int& x; // ERROR!
const int y; // ERROR!

Those objects cannot be re-assigned after initialization: thus, it makes sense that they have to be value-initialized, and that you won't be allowed to execute the body of your class's constructor with such member variables uninitialized.

Therefore, when you do have a choice, for fundamental types there is no difference between the two forms - just keep in mind that there are situations where you do not have a choice.

On the other hand, if your member variables are of class type, then the difference is that without an initialization list they will be default-constructed (if possible at all) and then assigned in the constructor's body; with an initialization list, they will be directly constructed with the arguments you specify.

Notice that C++11 gives you an additional possibility:

class MyClass {
public:
    int m_classID = -1;
    void *m_userdata = nullptr;
};
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
2

The initializer list lets you call the constructor of the member variables.

If you initialize in the body of the constructor, you're calling operator= (assignment), not the constructor.

The difference is akin to the difference between these two forms:

int three(3);            // Constructor argument
int three; three = 3;    // Assignment after construction

This makes a difference for members who do not have default constructors (i.e. constructors with no arguments), and for members whose values must be set when they are created (like references and constants).

So, it's only possible to initialize certain varieties of members in the constructor body; but all varieties of members can be initialized in an initializer list. This, and the fact that the default constructor isn't called for initializer-list-initialized members (which makes a difference for complex objects, but doesn't matter for, say, integers), means that it's generally preferable to use an initializer list, given the choice.

Cameron
  • 96,106
  • 25
  • 196
  • 225
1

For the case you give, there is no direct difference - there is a slight difference in the ORDER that initializer lists are ACTUALLY initialized (the order the members are declared), where in the second example, if you were to swap the line saying m_classID=-1 with the m_userdata = 0, they would indeed he initialized in the opposite order.

You can not initialize references or const values outside of an initializer list, so:

class bleh
{
   int& m_x;
   bleh(int x)
   {
      m_x = x;
   }
};

would give you some sort of error.

class bleh
{
   int& m_x;
   bleh(int x): m_x(x)
   {
   }
};

is the correct way.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
1

Just to point out a difference in c++11:

class MyClass {
public:
    MyClass(std::string str) : m_str(str) { }
private:
    std::string m_str;
};

is equivalent to doing

class MyClass {
public:
    MyClass(std::string str) { m_str = std::move(str); }
private:
    std::string m_str;
};

where as:

class MyClass {
public:
    MyClass(std::string str) { m_str = str; }
private:
    std::string m_str;
};

is only calling the assignment operator.

I ran into this problem because I was initializing objects in Lua, and when they were being destructed the strings were being cleaned up twice causing a sigtrap since Lua thought it controlled ownership of the string being passed in, but once it's moved that's no longer the case.

I know this doesn't fully answer the question, but the other answers didn't deal with this directly.

Lambage
  • 367
  • 3
  • 8
0

There are somethings you just can't initialize without the MIL, such as reference members.

class MyClass {
public:

    MyClass(MyOtherClass& otherClass)
         : m_classID(-1)
         , m_userdata(otherClass)
    { 
    }

    int m_classID;
    MyOtherClass& m_userdata;
};

Also, it is the only way to intizlize const members.

user1708860
  • 1,683
  • 13
  • 32
0

Initalization lists are preferable because

  1. You can use them with references
  2. You avoid running a default constructor + operator=, just a neccecary constructor which is faster. If the default constructor is private, you must use an initializer list
Dmitry Galchinsky
  • 2,181
  • 2
  • 14
  • 15