π 2015-Nov-02 ⬩ βοΈ Ashwin Nanjappa ⬩ π·οΈ cpp, uniform initialization ⬩ π Archive
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
10}
Line() : p {}, q {
{}
int x, int y) : p {x}, q{y}
Line(
{}
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
// .x = 0, .y = 0, .z = 45
Point p0 {}; 99}; // .x = 99, .y = 0, .z = 45
Point p1 {99, 15, 24}; // .x = 99, .y = 15, .z = 24
Point p2 {
// Init struct/class (with ctor)
// .p = 0, .q = 10, .r = 99
Line s0 {}; 10, 11}; // .p = 10, .q = 11, .r = 99
Line s2 {10}; // Error! No matching ctor found!
Line s1 {10, 11, 13}; // Error! No matching ctor found!
Line s3 {
/**
* 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;
}
Tried with: GCC 5.1 and Ubuntu 14.04