{}-Initialization - ModernesCpp.com (2023)


The initialization of variables was uniformed in C++11. The rule is quite simple. {}-Initialization is always applicable.

Always applicable

For simplicity reasons I will speak in the rest of the post about {}-Initialization, although I mean uniformed initialization with {}. But before I speak about two important implications of the {}-Initialization in safety-critical software I will show a few special use cases. This uses cases that require C++11.

 1 2 3 4 5 6 7 8 910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
// uniformInitialization.cpp#include <map>#include <vector>#include <string>// Initialization of a C-Array as attribute of a classclass Array{ public: Array(): myData{1,2,3,4,5}{} private: int myData[5];};class MyClass{ public: int x; double y;};class MyClass2{ public: MyClass2(int fir, double sec):x{fir},y{sec} {}; private: int x; double y;};int main(){ // Direct Initialization of a standard container int intArray[]= {1,2,3,4,5}; std::vector<int> intArray1{1,2,3,4,5}; std::map<std::string,int> myMap{{"Scott",1976}, {"Dijkstra",1972}}; // Initialization of a const heap array const float* pData= new const float[3]{1.1,2.2,3.3}; Array arr; // Defaut Initialization of a arbitrary object  int i{}; // i becomes 0 std::string s{}; // s becomes "" std::vector<float> v{}; // v becomes an empty vector double d{}; // d becomes 0.0 // Initializations of an arbitrary object using public attributes MyClass myClass{2011,3.14}; MyClass myClass1= {2011,3.14}; // Initializations of an arbitrary object using the constructor MyClass2 myClass2{2011,3.14}; MyClass2 myClass3= {2011,3.14}; }

First things first. The direct initialization of the C array, the std::vector, and the std::map (line 32 - 34) is quite easy. In the case of the std::map the inner {}-pairs are the key and value pairs. The next special use case is the direct initialization of a const C array on the heap (line 36). Special about the array arr in line 39 is that C arrays can be directly initialized in the constructor initializer (line 10). The default initialization in lines 42 to 45 looks quite innocent. But if I use round brackets instead of curly brackets, the most vexing parse will happen. That does not sound good. Why? Wait for the next section. I directly initialize in lines 48 and 49 the public attributes of the objects. It's also possible to call the constructor with curly braces (lines 52 and 53).

{}-Initialization - ModernesCpp.com (1)Modernes C++ Mentoring

Stay informed about my mentoring programs. Subscribe for the news.


Always applicable? Yes, but you have to keep a special rule in mind. If you use automatic type deduction with auto in combination with an {}-initialization, you will get a std::initializer_list.

 auto initA{1}; // std::initializer_list<int> auto initB= {2}; // std::initializer_list<int> auto initC{1, 2}; // std::initializer_list<int> auto initD= {1, 2}; // std::initializer_list<int>

This behavior will change very likely in C++17.

 auto initA{1}; // int auto initB= {2}; // std::initializer_list<int> auto initC{1, 2}; // error, no single element auto initD= {1, 2}; // std::initializer_list<int>

To be honest, I don't like this change. The C++11 semantic is quite clear to me. If I use {}-initialization with auto, I will get an initializer list. With C++17 I have to keep the two exceptions with auto in my head.

  1. It makes a difference if you use direct or copy initialization.
  2. It makes a difference if you use {}-initialization with one or more elements.

Most vexing parse

But what does that mean? Seems to be a well-known expression: https://en.wikipedia.org/wiki/Most_vexing_parse. The story is quickly told. Most C++ developers know them personally.

At first, a small program shows the issue.

 1 2 3 4 5 6 7 8 91011121314151617181920
// parse.cpp#include <iostream>struct MyInt{ MyInt(int i):i(i){} MyInt():i(0){} int i;};int main(){ MyInt myInt(2011); MyInt myInt2(); std::cout << myInt.i << std::endl; std::cout << myInt2.i << std::endl; }

MyInt in lines 5 - 9 is a simple wrapper for the natural number i. The constructor in line 6 sets i to an explicit value. On the opposite, the default constructor in line 7 sets i to 0. So far so good. I use in lines 14 and 15 both constructors and display the values of i. Compile and run, that's all I have to do.

But wait. The program does not compile.

{}-Initialization - ModernesCpp.com (2)

The error message is not so meaningful. The compiler can interpret the expression in line 15 as a call of a constructor or as a declaration of a function. In case of doubt, it interprets the expression as a function declaration. The slightly modified program shows it.

 1 2 3 4 5 6 7 8 910111213141516171819202122
// parseResolved.cpp#include <iostream>#include <typeinfo>struct MyInt{ MyInt(int i):i(i){} MyInt():i(0){} int i;};MyInt myFunction();int main(){ MyInt myInt(2011); MyInt myInt2(); std::cout << typeid(myInt2).name() << std::endl; std::cout << typeid(myFunction).name() << std::endl;}

I declare in line 12 the function myFunction that has no arguments and returns a type MyInt. myFunction has the same signature as the function declarations in line 17. Thanks to the typeid operator, the output of the program shows exactly that.

{}-Initialization - ModernesCpp.com (3)

The solutions to the problem are quite easy. If I use curly braces in lines 12 and 17, the compiler will not interpret both lines as the function declaration. I already used this characteristic of the {}-initialization in the first example of this post (line 42 - 45).

But now to the main topic of this post, which is so precious for software in safety-critical systems: preventing narrowing.

Preventing narrowing

Narrowing or more precise narrowing conversion is an implicit conversion of arithmetic values including a loss of accuracy. That sounds extremely dangerous.

The following example shows the issue with the classical initialization for fundamental types. It doesn't matter whether I use direct initialization or assignment.

 1 2 3 4 5 6 7 8 91011121314151617
// narrowing.cpp#include <iostream>int main(){ char c1(999); char c2= 999; std::cout << "c1: " << c1 << std::endl; std::cout << "c2: " << c2 << std::endl; int i1(3.14); int i2= 3.14; std::cout << "i1: " << i1 << std::endl; std::cout << "i2: " << i2 << std::endl;}

The output of the program shows two issues. First, the int literal 999 doesn't fit into the type char; second, the double literal doesn't fit into the int type.

{}-Initialization - ModernesCpp.com (4)

That is not possible with {}-initialization.

 1 2 3 4 5 6 7 8 91011121314151617
// narrowingSolved.cpp#include <iostream>int main(){ char c1{999}; char c2= {999}; std::cout << "c1: " << c1 << std::endl; std::cout << "c2: " << c2 << std::endl; int i1{3.14}; int i2= {3.14}; std::cout << "i1: " << i1 << std::endl; std::cout << "i2: " << i2 << std::endl;}

The program is ill-formed. Because of the narrowing with {}-Initialization the compiler has at least to diagnose a warning. Although the program is ill-formed, the compiler has not rejected it.

But now the maximum confusion with GCC begins. It makes a difference whether I use GCC 4.7 or GCC 4.8. GCC 4.7 rejected the program; GCC 4.8 only provides a warning. With GCC 5.1 we get an error. You don't believe me? Try it out with the online compiler https://gcc.godbolt.org/. The clang++ compiler is much more predictable. Therefore my tip. Compile your program in such a way that narrowing is an error. So did I. I used the flag -Werror=narrowing and GCC 4.8 complains about the program.

{}-Initialization - ModernesCpp.com (5)

A small remark at the end. The expression char c3{8} is indeed no narrowing because 8 fits in the type char. The same holds for char c3= {8}.

What's next?

C++11 got with static_assert the type-traits library two powerful features for checking the source code at compile time. I the next post I will have a deeper look into static_assert and its combination with the functions of the type-traits library.

Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, Marko, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Louis St-Amour, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Neil Wang, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Evangelos Denaxas, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, and Wolfgang Fütterer.

Thanks in particular to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, Ralf Abramowitsch, John Nebel, Mipko, Alicja Kaminska, and Matthias Grün.

My special thanks to Embarcadero {}-Initialization - ModernesCpp.com (6)

My special thanks to PVS-Studio {}-Initialization - ModernesCpp.com (7)


I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)


Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.


Contact Me

Modernes C++,

{}-Initialization - ModernesCpp.com (8)

Top Articles
Latest Posts
Article information

Author: Carmelo Roob

Last Updated: 01/21/2023

Views: 6507

Rating: 4.4 / 5 (45 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Carmelo Roob

Birthday: 1995-01-09

Address: Apt. 915 481 Sipes Cliff, New Gonzalobury, CO 80176

Phone: +6773780339780

Job: Sales Executive

Hobby: Gaming, Jogging, Rugby, Video gaming, Handball, Ice skating, Web surfing

Introduction: My name is Carmelo Roob, I am a modern, handsome, delightful, comfortable, attractive, vast, good person who loves writing and wants to share my knowledge and understanding with you.