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.

Share the Post:
XDR solutions

The Benefits of Using XDR Solutions

Cybercriminals constantly adapt their strategies, developing newer, more powerful, and intelligent ways to attack your network. Since security professionals must innovate as well, more conventional endpoint detection solutions have evolved

AI is revolutionizing fraud detection

How AI is Revolutionizing Fraud Detection

Artificial intelligence – commonly known as AI – means a form of technology with multiple uses. As a result, it has become extremely valuable to a number of businesses across

AI innovation

Companies Leading AI Innovation in 2023

Artificial intelligence (AI) has been transforming industries and revolutionizing business operations. AI’s potential to enhance efficiency and productivity has become crucial to many businesses. As we move into 2023, several

data fivetran pricing

Fivetran Pricing Explained

One of the biggest trends of the 21st century is the massive surge in analytics. Analytics is the process of utilizing data to drive future decision-making. With so much of

kubernetes logging

Kubernetes Logging: What You Need to Know

Kubernetes from Google is one of the most popular open-source and free container management solutions made to make managing and deploying applications easier. It has a solid architecture that makes

ransomware cyber attack

Why Is Ransomware Such a Major Threat?

One of the most significant cyber threats faced by modern organizations is a ransomware attack. Ransomware attacks have grown in both sophistication and frequency over the past few years, forcing

data dictionary

Tools You Need to Make a Data Dictionary

Data dictionaries are crucial for organizations of all sizes that deal with large amounts of data. they are centralized repositories of all the data in organizations, including metadata such as