In-class member initializers
In C++98, only static const members of integral types can be initialized in-class, and the initializer has to be a constant expression. These restrictions ensure that we can do the initialization at compile-time. For example:
int var = 7;
class X {
static const int m1 = 7; // ok
const int m2 = 7; // error: not static
static int m3 = 7; // error: not const
static const int m4 = var; // error: initializer not constant expression
static const string m5 = "odd"; // error: not integral type
// ...
};
The basic idea for C++11 is to allow a non-static data member to be initialized where it is declared (in its class). A constructor can then use the initializer when run-time initialization is needed. Consider:
class A {
public:
int a = 7;
};
This is equivalent to:
class A {
public:
int a;
A() : a(7) {}
};
This saves a bit of typing, but the real benefits come in classes with multiple constructors. Often, all constructors use a common initializer for a member:
class A {
public:
A(): a(7), b(5), hash_algorithm("MD5"), s("Constructor run") {}
A(int a_val) : a(a_val), b(5), hash_algorithm("MD5"), s("Constructor run") {}
A(D d) : a(7), b(g(d)), hash_algorithm("MD5"), s("Constructor run") {}
int a, b;
private:
HashingFunction hash_algorithm; // Cryptographic hash to be applied to all A instances
std::string s; // String indicating state in object lifecycle
};
The fact that hash_algorithm and s each has a single default is lost in the mess of code and could easily become a problem during maintenance. Instead, we can factor out the initialization of the data members:
class A {
public:
A(): a(7), b(5) {}
A(int a_val) : a(a_val), b(5) {}
A(D d) : a(7), b(g(d)) {}
int a, b;
private:
HashingFunction hash_algorithm{"MD5"}; // Cryptographic hash to be applied to all A instances
std::string s{"Constructor run"}; // String indicating state in object lifecycle
};
If a member is initialized by both an in-class initializer and a constructor, only the constructor's initialization is done (it "overrides" the default). So we can simplify further:
class A {
public:
A() {}
A(int a_val) : a(a_val) {}
A(D d) : b(g(d)) {}
int a = 7;
int b = 5;
private:
HashingFunction hash_algorithm{"MD5"}; // Cryptographic hash to be applied to all A instances
std::string s{"Constructor run"}; // String indicating state in object lifecycle
};