In this specific case, is there a difference between using a member initializer list and assigning values in a constructor?

Solution 1:

You need to use initialization list to initialize constant members,references and base class

When you need to initialize constant member, references and pass parameters to base class constructors, as mentioned in comments, you need to use initialization list.

struct aa
{
    int i;
    const int ci;       // constant member

    aa() : i(0) {} // will fail, constant member not initialized
};

struct aa
{
    int i;
    const int ci;

    aa() : i(0) { ci = 3;} // will fail, ci is constant
};

struct aa
{
    int i;
    const int ci;

    aa() : i(0), ci(3) {} // works
};

Example (non exhaustive) class/struct contains reference:

struct bb {};

struct aa
{
    bb& rb;
    aa(bb& b ) : rb(b) {}
};

// usage:

bb b;
aa a(b);

And example of initializing base class that requires a parameter (e.g. no default constructor):

struct bb {};

struct dd
{
    char c;
    dd(char x) : c(x) {}
};

struct aa : dd
{
    bb& rb;
    aa(bb& b ) : dd('a'), rb(b) {}
};

Solution 2:

Assuming that those values are primitive types, then no, there's no difference. Initialization lists only make a difference when you have objects as members, since instead of using default initialization followed by assignment, the initialization list lets you initialize the object to its final value. This can actually be noticeably faster.

Solution 3:

Yes. In the first case you can declare _capacity, _data and _len as constants:

class MyClass
{
private:
    const int _capacity;
    const void *_data;
    const int _len;
// ...
};

This would be important if you want to ensure const-ness of these instance variables while computing their values at runtime, for example:

MyClass::MyClass() :
    _capacity(someMethod()),
    _data(someOtherMethod()),
    _len(yetAnotherMethod())
{
}

const instances must be initialized in the initializer list or the underlying types must provide public parameterless constructors (which primitive types do).

Solution 4:

I think this link http://www.cplusplus.com/forum/articles/17820/ gives an excellent explanation - especially for those new to C++.

The reason why intialiser lists are more efficient is that within the constructor body, only assignments take place, not initialisation. So if you are dealing with a non-built-in type, the default constructor for that object has already been called before the body of the constructor has been entered. Inside the constructor body, you are assigning a value to that object.

In effect, this is a call to the default constructor followed by a call to the copy-assignment operator. The initialiser list allows you to call the copy constructor directly, and this can sometimes be significantly faster (recall that the initialiser list is before the body of the constructor)