Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

New Initialization Syntax

Last updated Jan 1, 2003.

C++03 has many different and confusing syntactic forms for initialization. In addition, there is no way to initialize containers, POD member arrays, and dynamically allocated POD arrays. The C++09 standard fixes these problems with a new uniform initialization syntax.
C++03 Initializer Babel

C++03 distinguishes between two major categories of objects when initialization is concerned: aggregates and class objects. An aggregate uses braces for initialization:

int n[2]={0,1};
struct S //aggregate
{
 int x,y;
};
S s={0,1}; 

Class objects with a user-defined constructor cannot use the brace notation. Instead, they use an initializer list enclosed in parentheses:

struct S1
{
explicit S(int i int j) : x(i),y(j){};
private:
 int x, y;
};
S1 s(0,1); //parentheses required instead of braces 

Alternatively, class objects with a user-defined constructor may use default initialization, copy-construction syntax or an assignment operator syntax for their initialization:

std::string s1; //default initialization
std::string s2=("hello"); //parentheses with an initializer
std::string s3(s2); //copy constructor initialization
std::string s4=s2;//copy constructor initialization that uses the = notation

Arrays

Arrays of class objects are even more perplexing. In most cases, they do not include an explicit initializer at all. Instead, each array element is default initialized:

std::string s[10]; //default initialization
std::string *ps=new string[2];//default initialization

As opposed to a common belief, there is a way to use the non-default constructor in an array initialization. However, this form of initialization is inconvenient and cannot be used with dynamically allocated arrays:

std::string s[2]= {string("ab"), string("cd")};
std::string s2[2]= {("ab"), ("cd")}; //same as above but shorter
std::string *ps=new string[2]={"ab", "cd"};//compilation error 

Classes that have arrays of POD types as data members are another known problem. There is no way to initialize array members at all:

class C
{
int n[5];
double *pd;
public: 
 C(): n(0,1,2,3,4) {}//compilation error
 explicit C(int i, int j, int k, int l, int m): {n={i,j,k,l,m}; }//also a compilation error
 explicit C(int sz): pd(new double[sz]) {} //how to initialize the array pd?
};

You can look for creative syntactic notations but that won't do -- in C++03 there simply is no way to initialize the member array n nor is there a way to initialize the elements of pd. Instead, programmers tend to assign, rather than initialize, these members manually:

explicit C::C(int sz): pd(new double[sz]) 
{
 for (int i=0; i<sz; i++) 
 { //manual assignment used as "initialization"
  pd[i]=0; 
  n[i]=i
 } 
}

Containers

Things get messier when you use containers. Suppose you have a vector of strings that you want to initialize. In C++03, you have to "initialize" such a container manually using a sequence of push_back() calls:

vector <string> vs;

vs.push_back("ab");

vs.push_back("cd");

vs.push_back("ef");

Conclusion: C++03 Initialization is Messy

The confusing rules regarding initialization are particularly problematic when it comes to templates. A template can't tell whether its argument t is a class object, an aggregate or a fundamental type unless you resort to type traits that often lead to obfuscated code and design compromises. In addition, C++ programmers find it hard to follow the seemingly arbitrary and inconsistent rules of initialization. The C++ standards committee agreed that these inconsistent initialization rules needed a thorough reform. At last, the C++09 Committee Draft introduces a new syntactic notation for initialization.

C++09 New Initialization Syntax

In June 2008 the C++ standards committee voted in a new proposal for a uniform initialization notation for class objects, arrays, aggregates, dynamically allocated arrays and even containers. Generally speaking, the new rules allow you to use braces more liberally. For example, you can initialize an object that has a user-defined constructor like this:

class C
{
int a;
int b;
public:
 C(int i, int j);
};
// C++0x object initializer
C c ={0,0}; //C++09 only. Equivalent to: C c(0,0);

Of course, the traditional parenthesized initializer is still valid in C++09.

With respect to containers, you can say goodbye to a tedious list of push_back() calls. In C++09, you initialize standard containers intuitively with braces:

// C++09 container initializer
vector<string> vs={ "ab", "cd", "ef"};
map<string, string> rescue_team =
 { {"Tim Geithner", "+1 (212) 555-7890"},
  {"Larry Summers", "+1 (212) 555-0987"}};

How does it work? Under the hood, all C++09 Standard Library container classes use a special constructor called a sequence constructor (I will discuss this topic in a separate column). Without getting into the technical details, these sequence constructors make the containers initializations above "just work".

Finally, we're getting to the onerous problems of member arrays and dynamically allocated arrays. C++09 allows you to use braces to initialize them intuitively and safely. Here's an example of a C++09 array member initialization:

class C
{
int n[5];
public: 
 C(): n{0,1,2,3,4} {}//C++09 only
};

Similarly, you can now initialize a dynamically-allocated array like this:

int* pi = new int[4] {1,2,3,4};//C++09 initialization

Compiler Support

Certain compilers (GCC 4.4 for example) already support the new initialization syntax. Other compilers will surely follow suit in their forthcoming releases.