Use Class Member Initializers for Cleaner and Easier-to-Maintain Constructors

Use Class Member Initializers for Cleaner and Easier-to-Maintain Constructors

ormally, you initialize data members in a constructor’s member initialization list. When a class has multiple constructors, each constructor initializes the object’s members individually, which often leads to repeating the same initialization code in various places. The use of delegating constructors solves this problem to some extent, but there are cases in which you still need to repeat the initializers, thus risking maintenance difficulties and compromising code readability. This 10-Minute Solution presents a new technique for eliminating repeated initialization code.

Your class has multiple constructors, forcing you to repeat data member initialization code in every constructor.

Use class member initializers to initialize a data member only once.

The Repeated Initializers Problem

In contemporary C++, a member-declarator can contain a constant initializer only if the affected member is both static and of a const integral type, or if it’s a const enumeration type. For example, the following is allowed in C++98 and C++03:

class A{  static const int MAX=1024;  public:  A();  //..};

However, the next class declaration example is ill-formed because b is neither a const static data member of an integral type nor a const enumeration:

class C{  int b=1024; //error  bool f;  double d;  //..};

Because of this restriction, programmers are forced to repeat the initialization of b in every constructor of class C:

class C{  int b;  bool f;  double d;  public:    C(): b(1024), f(false), d(0.0) {}    C(bool flag) : b(1024), f(flag), d(0.0) {}    C(bool flag, double dbl): b(1024), f(flag), d(dbl){}};

Such repetition is both laborious and error prone. Why not let a programmer specify the initializer for b only once? A new C++0x proposal allows you to do exactly that—and even more.

Enter Class Member Initializers

Before explaining what class member initializers are, I feel obliged to clarify the terminology to avoid any confusion between related but distinct concepts.

A member-initialization list appears in a constructor declaration right after the parameter list and is preceded by a colon:

class A{  int x;  int y;public:  A(): x(2), y(3){}  };
Author’s Note: Recall that the order of the initializers in a member initialization list should match the order of the members’ declaration in the class.

An initializer_list is a standard C++09 class template defined in . Sequence constructors use an initializer_list to transform an arbitrary set of initializers into a range, thereby letting you initialize objects with a variable number of initializers.

template  class vector {  public:    vector(std::initializer_list s);};vector vi={1,8,102,99};

A class member initializer is a new C++0x proposal described in the following sections. Do not confuse it with the two aforementioned initialization constructs.

Syntactically, a class member initializer looks like this:

class D{  public:    int x=5; //class member initializer, C++0x only    int y(6); //another class member initializer};

The compiler conceptually transforms a class member initializer into a member initializer list. Thus, the declaration of class D above is silently transformed into the following:

class D{  public:    int x;    D(): x(5), y(6) {}};

From a programmer’s point of view, the class member initializer feature might not seem like a significant improvement (except perhaps for the more intuitive syntax). However, the advantages of a class member initializer become apparent when your class has multiple constructors. Here’s a revised version of class C that uses a class member initializer for b:

class C{  int b=1024;//class member initializer, C++0x  bool f;  double d; public:  C(): f(false), d(0.0) {}  C(bool flag) : f(flag), d(0.0) {}  C(bool flag, double dbl): f(flag), d(dbl){}};

The constructor-dependent data members f and d appear in each constructor’s member initialization list, as before. However, notice that b is now initialized only once, regardless of the specific constructor used.

Defaults and Overrides

A class member initializer is capable of doing more than what you’ve just seen. In the preceding version of class C, look at the data member d. The first two constructors initialize d to 0.0. Only the third constructor initializes d to a different value. In such cases, you can specify a default initializer in a class member initializer, and override that initializer by an explicit member initializer when necessary. The following code functions equivalently, but uses a class member initializer to initialize d:

class C{  int b=1024;   bool f;  double d=0.0;  //default value for d public:  C(): f(false) {} //b initialized to 1024, d to 0.0  C(bool flag) : f(flag) {} //same here  C(bool flag, double dbl): f(flag), d(dbl){}};

A constructor whose member-initializer list doesn’t contain an explicit initializer for d will use the default initializer—the class member initializer. Consequently, in the preceding example, the first two constructors will initialize d to 0.0 (and b to 1024), whereas the third constructor will initialize d to dbl.

With this generalization in mind, you can simplify the constructors for class C even further by assigning a class member initializer to f as well:

class C{  int b=1024;   bool f=false;   double d=0.0; public:  C(){}  C(bool flag): f(flag) {}  C(bool flag, double dbl): f(flag), d(dbl){}};

To summarize, a constructor should include an explicit member initializer only when it needs to override the default initializer specified in the respective data member’s declaration. Notice that data members that have no initializer will have an indeterminate value, as always:

class G{ public:   std::string x("TEST"); //class member init for string   int y;   int z;   G(): z(0){}//initialize x and z, y has an undefined value};

At the time of this writing, the class member initializers proposal has a very good chance of being incorporated into C++0x. You can get updates on various compilers’ C++0x support here.


About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist