C++ 2011: Uniform Initialization

In C++, initializing objects is not done in the same manner in all contexts. The rules for initialization and constructors are not really simple and developers sometimes have to write lot of explicit code for initializing objects. Fortunately the new C++ standard comes to the rescue, offering a uniform initialization syntax and semantics.

The way it was before C++ 2011

Let's take the following structure as a start point.

struct Color
{
    unsigned char A;
    unsigned char R;
    unsigned char G;
    unsigned char B;
};

If you want to initialize an object of this type, then you can write:

Color c;
c.A = 0xff;
c.R = 0xff;
c.G = 0x00;
c.B = 0x00;

But there is a simpler way to write that:

Color c = {0xff, 0xff, 0x00, 0x00};

If you want to zero the entire structure, then you can write:

Color c = {0};

However, you cannot use this initialization type to initialize all the members with 0xff, for instance. If you write

Color c = {0xff};

then only A will be 0xff, the other fields would be initialized with a default value, which is 0.

Since this is a POD (Plain Old Data) type (which is a scalar or a POD class - a class with no user defined constructors or destructor, no user defined copy assignment operator, no base classes or virtual functions, no private or protected non-static data and no static data that is non-POD types) you could also write:

memset(&c, 0, sizeof(c));

Mind you, initializing with 0 with memset works for any POD type, however, initializing with another value, say 1, will not have the expected result; if A, R, G and B would have been ints for instance, because memset puts the specified value in every byte starting at the specified address for the specified count, you'd get ints that are 0x01010101 instead of simply 1.

When it comes to array you can initialize all the elements of the array with 0 as in:

Color ca[2] = {0};

which is identical to

Color ca[2] = {{0}, {0}};

However, if you want to initialize with something other than 0, then you can write:

Color ca[2] = {{0}, {0xff, 0xff, 0x00, 0x00}};

Now, another way to initialize Color would be to define a constructor (which makes the type non-POD, so no more memset). The default value of the constructor parameters allow you to declare arrays of this object. Otherwise, since there is no default constructor, it wouldn't be possible to declare an array of Color.

struct Color
{
    unsigned char A;
    unsigned char R;
    unsigned char G;
    unsigned char B;
 
    Color(
       unsigned char a = 0, 
       unsigned char r = 0,
       unsigned char g = 0,
       unsigned char b = 0): A(a), R(r), G(g), B(b)
    {}
};

In this case you can say:

Color c(0xff, 0xff, 0x00, 0x00);

However, since Color is no longer an aggregate (because it has a user defined constructor) this initialization is no longer supported; the following issues errors:

Color c = {0xff, 0xff, 0x00, 0x00};

Color ca[2] = {{0}, {0xff, 0xff, 0x00, 0x00}};

If instead of using an array, we'd want to use a vector of Color, then initializing it would be only possible like this:

vector<Color> cv;
cv.push_back(Color(0));
cv.push_back(Color(0xff, 0xff, 0x00, 0x00));

Or

vector<Color> ca(2);
ca[1] = Color(0xff, 0xff, 0x00, 0x00);

Or

ca[1].A = 0xff;
ca[1].R = 0xff;
ca[1].G = 0x00;
ca[1].B = 0x00;

Or if you'd have an array of Color, then you can say:

Color ca[2] = {Color(0), Color(0xff, 0xff, 0x00, 0x00)};
vector<Color> cv(ca, ca+2);

Enter C++ 2011

The new standard introduces a new way of initializing objects, in a more uniform manner. Even though Color is a non-POD type you can write:

Color c {0xff, 0xff, 0x00, 0x00};

Color ca[2] {{0}, {0xff, 0xff, 0x00, 0x00}};

vector<Color> ca {{0}, {0xff, 0xff, 0x00, 0x00}};

Or (these two being identical)

Color c = {0xff, 0xff, 0x00, 0x00};

Color ca[2] = {{0}, {0xff, 0xff, 0x00, 0x00}};

vector<Color> ca = {{0}, {0xff, 0xff, 0x00, 0x00}};

Or with a map:

map<string, Color> colors = {
  {"red",     {0xff, 0xff, 0x00, 0x00}},
  {"green",   {0xff, 0x00, 0xff, 0x00}},
  {"blue",    {0xff, 0x00, 0x00, 0xff}},
};

It is important to note that the initialization with the parenthesis, as shown in the previous paragraph as the only way to initialize non-POD types before C++ 2011, is still available.

Also note that in the following code sample, the first vector will have three elements (initialized with the default value), while the second will have a single element with value 3.

vector vec1(3);
vector vec2{3};

If the array or the vector were members of a class, the following initialization could be done:

class foo
{
   int data[3];
public:
   foo(): data{1,2,3} {}
};

class bar
{
   vector data;
public:
   bar(): data{1,2,3} {}
};

What if the array would be dynamically allocated on the heap? Then, you can use the same initialization syntax with {}:

int* data = new int[3] {1,2,3};

Or, in case it is part of a class

class foobar
{
   int* data;
public:
   foobar(): data(new int[3]{1,2,3}){}
};

It is also possible to use the curly braces to initialize an object in a return statement:

Color make_color(unsigned char r, unsigned char g, unsigned char b)
{
   return {0xff, r, g, b};
}

Or for a function call:

void use_color(Color c)
{
}

use_color({0xff, 0xff, 0x00, 0x00});

Conclusions

The new C++ standard brings a new, uniform initialization syntax and semantics, helping developers to write simpler and uniform code. Using the curly braces {} constructs the same value in all contexts where it is legal. Unfortunately, not all compilers support this new feature at the time of writing this article, but they will pretty soon.



About the Author

Marius Bancila

Marius Bancila is a Microsoft MVP for VC++. He works as a software developer for a Norwegian-based company. He is mainly focused on building desktop applications with MFC and VC#. He keeps a blog at www.mariusbancila.ro/blog, focused on Windows programming. He is the co-founder of codexpert.ro, a community for Romanian C++/VC++ programmers.

Related Articles

Comments

  • Loan Tips

    Posted by Loanemu.com on 10/14/2015 01:54am

    Marvelous details, thank you to the creator.

    Reply
  • cheap nfl jerseys

    Posted by effenlynagige on 10/19/2012 03:37am

    supermarket cheap nfl jerseys , Questions cheap nfl jerseys , that's cheap nfl jerseys , The modern cheap nfl jerseys , has produced cheap nfl jerseys , essential to cheap nfl jerseys , kept in cheap nfl jerseys , that are cheap nfl jerseys , is usually a cheap nfl jerseys , a lot of cheap nfl jerseys ,

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date