Browse DevX
Sign up for e-mail newsletters from DevX


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

A new C++0x feature called a class member initializer allows you to specify a single initializer in the very declaration of a data member. Learn how to use this feature to simplify your constructors' code, reduce potential bugs, and make your code more readable.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

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 <initializer_list>. 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 T> class vector { public: vector(std::initializer_list<T> s); }; vector<int> 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.

Danny Kalev is a certified system analyst and software engineer specializing in C++. He was a member of the C++ standards committee between 1997 and 2000 and has since been involved informally in the C++0x standardization process. He is the author of "The ANSI/ISO Professional C++ Programmer's Handbook" and "The Informit C++ Reference Guide: Techniques, Insight, and Practical Advice on C++."
Thanks for your registration, follow us on our social networks to keep up-to-date