Uniform initialization in C++

Initializing in C++98 used to be a pain:

  • There were multiple ways to initialize: using = or () or {}.

  • Some types of initialization of user types was either difficult or not possible to support.

  • You could not initialize variable of a builtin type to its default value (like in Java). C or C++ only default-initialize in global scope, not in non-global scope.

  • No way to initialize a container (like std::vector or your own) with a series of non-default values.

C++11 introduced an uniform initialization syntax using {} that makes writing and reading C++ a joy! In my opinion, this is a feature that will make everyone’s code easier to write and read. Though it does have a few rough edges (since C++ has to support all previous syntaxes), it almost always works in a way that is most intuitive to the viewer.

It is called uniform initialization because it is applicable in every place where you initialize anything. That includes: variables, constants, objects, in the initializer list of a constructor and even in the member declaration of a struct or class. Everywhere!

I am sharing a code sample below that enumerates the various ways to apply this syntax:

#include <iostream>
#include <stack>
#include <unordered_set>
#include <vector>
class Point
{
public:
int x;
int y;
int z {45}; // Look ma! Default init of member!
};
class Line
{
public:
// In initializer list
Line() : p {}, q {10}
{}
Line(int x, int y) : p {x}, q{y}
{}
int p;
int q;
int r {99}; // Look ma! Default init outside ctor!
};
int main()
{
// Init with default values of builtin types
{
char c {}; // c = 0
int i {}; // i = 0
float f {}; // f = 0.0f
double d {}; // d = 0.0
bool b {}; // b = false
std::string s {}; // s = ""
int* p {}; // p = nullptr
}
// Init with specific values
{
char c {'x'}; // c = 'x'
int i {99}; // i = 99
float f {3.14f}; // f = 3.14f
double d {1.23}; // d = 1.23
bool b {true}; // b = true
std::string s {"cat"}; // s = "cat"
int* p {&i}; // p = &i
}
// Narrowing convertions not allowed
// This can be based on type (float-to-int) or actual value (int-to-char)
{
int i {3}; // OK
int j {3.0}; // Error!
int k {3.14}; // Error!
}
// Init array values
int i_arr[5] {}; // [0, 0, 0, 0, 0]
int j_arr[] {99, 10, 3}; // [99, 10, 3]
int k_arr[5] {99, 10, 3}; // [99, 10, 3, 0, 0]
int m_arr[5] {99, 10, 3, 5, 7}; // [99, 10, 3, 5, 7]
// Init struct/class members (with no ctor)
// See above for definition of Point class
Point p0 {}; // .x = 0, .y = 0, .z = 45
Point p1 {99}; // .x = 99, .y = 0, .z = 45
Point p2 {99, 15, 24}; // .x = 99, .y = 15, .z = 24
// Init struct/class (with ctor)
Line s0 {}; // .p = 0, .q = 10, .r = 99
Line s2 {10, 11}; // .p = 10, .q = 11, .r = 99
Line s1 {10}; // Error! No matching ctor found!
Line s3 {10, 11, 13}; // Error! No matching ctor found!
/**
* Init STL vectors
*/
// Init vectors
std::vector<int> i_vec_0 {5}; // [5]
std::vector<int> i_vec_1 {5, 2}; // [5, 2]
std::vector<int> i_vec_2 {2, 3, 4, 5}; // [2, 3, 4, 5]
std::vector<int> i_vec_3 (5); // [0, 0, 0, 0, 0]
// A matching constructor is chosen over aggregation
// Note what happens on passing int
std::vector<std::string> s_vec_0 {}; // []
std::vector<std::string> s_vec_1 {"cat", "rat", "mat"}; // ["cat", "rat", "mat"]
std::vector<std::string> s_vec_2 {4}; // ["", "", "", ""]
std::vector<std::string> s_vec_3 {4, "ba"}; // ["ba", "ba", "ba", "ba"]
/**
* Other STL containers
*/
std::unordered_set<int> i_set {99, 32, 45, 32}; // [99, 32, 45]
return 0;
}

view raw
uni_init.cpp
hosted with ❤ by GitHub

Tried with: GCC 5.1 and Ubuntu 14.04

4 thoughts on “Uniform initialization in C++

  1. Note, that a narrowing conversion in this case is ill-formed and the compiler is required to generate a diagnostic but the diagnostic could be an error or a warning. There are several versions of gcc where this is only a warning.

    Like

    1. Syaghmour: Thanks! Could you point me to a relevant reference about the narrowing conversions? I couldn’t find enough info in Stroustrup’s book.

      Like

    2. Well cppreference gives a good summary http://en.cppreference.com/w/cpp/language/list_initialization#Narrowing_conversions . In a Stackoverflow answer I quote the gcc bug report that explains why some versions of gcc made it warning as opposed to an error: http://stackoverflow.com/a/31685448/1708801 . In that answer I cite the relevant sections from the draft C++11 standard as well as link to it. The C++ standard is always the best reference.

      This quote from Herb Sutter in another Stackoverflow answer on the same topic http://stackoverflow.com/questions/16939471/preventing-narrowing-conversion-when-using-stdinitializer-list#comment24463587_16939798 is a good read.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.