The second option is not initialization but assignment. With types that have user defined default constructors, the second option will call the default constructor and later on call the assignment operator (whether user defined or not) to assign the value.
Some types cannot be default initialized: If you have an attribute without default constructor, hold references (constant or not) or have constant attributes they must be initialized in the initializer list.
Arrays can be value-initialized in the initialization list, but not in the constructor body:
class X {
public:
X() : array() {} // value-initializes the array
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) array[i]=0; }
private:
int array[10];
};
For POD types, you can value-initialize them in the initialization list but not inside the brackets:
class X {
public:
X() : pod() {} // value-initializes
// equivalent to (but easier to read and subtly faster as it avoids the copy):
// X() { pod = {}; }
private:
PODType pod;
};
Finally, some classes offer functionality through the use of constructors that will be more complex (if achievable) after default construction.
class X
{
public:
X() : v(10) {} // construct a vector of 10 default initialized integers
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) v.push_back(0); }
private:
std::vector<int> v;
};
Last, whenever they are in fact equivalent, initialization lists are more idiomatic in C++.