{}-Initialization

Contents[Show]

The initialization of variables was unified 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 crucial 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
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// uniformInitialization.cpp

#include <map>
#include <vector>
#include <string>

// Initialization of a C-Array as attribute of a class
class 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 (lines 32 - 34) is relatively easy. In the case of the std::map, the inner {}-pairs are the key and value pairs. The following particular 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 entirely 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).

 

Rainer D 6 P2 540x540Modernes C++ Mentoring

Be part of my mentoring programs:

 

 

 

 

Do you want to stay informed about my mentoring programs: Subscribe via E-Mail.

auto

Always applicable? Yes, but you have to keep a particular 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>

 

I don't like this change. The C++11 semantic is quite clear to me. I will get an initializer list if I use {}-initialization with auto. 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? It 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
 9
10
11
12
13
14
15
16
17
18
19
20
// 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. Conversely, the default constructor in line 7 sets i to 0. So far, so good. I use both constructors in lines 14 and 15 and display the values of i. Compile and run; that's all I have to do.

But wait. The program does not compile.

 parse

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
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 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 program's output shows precisely that.

parseResolved

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 the main topic of this post, which is so precious for software in safety-critical systems: preventing narrowing.

Preventing narrowing

Narrowing or, more precisely, 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
 9
10
11
12
13
14
15
16
17
// 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.

narrowingUndefined

That is not possible with {}-initialization.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 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. Don't you 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.

 narrowing

A small remark at the end. The expression char c3{8} is indeed no narrowing because eight fits 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. In 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, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, 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, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, and Rob North.

 

Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

My special thanks to PVS-Studio PVC Logo

 

My special thanks to Tipi.build tipi.build logo

 

My special thanks to Take Up Code TakeUpCode 450 60

 

Seminars

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

Bookable (Online)

German

Standard Seminars (English/German)

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

  • C++ - The Core Language
  • C++ - The Standard Library
  • C++ - Compact
  • C++11 and C++14
  • Concurrency with Modern C++
  • Design Pattern and Architectural Pattern with C++
  • Embedded Programming with Modern C++
  • Generic Programming (Templates) with C++

New

  • Clean Code with Modern C++
  • C++20

Contact Me

Modernes C++,

RainerGrimmDunkelBlauSmall

 

 

Comments   

+1 #1 Shafik Yaghmour 2016-10-12 19:14
There are several confused Stackoverflow questions with respect to gcc and clang treating narrowing conversions differently. I discovered when answering this one: http://stackoverflow.com/a/31685448/1708801 that gcc changed to treating narrowing conversions as warnings due to porting issue but this was temporary.

I believe the fact that that a lot of books use the examples form the standard which use the non-normative "error" in comments adds to the confusion. Most users don't understand the distinction between diagnostic, error and warning.
Quote
-9 #2 marriage quotes 2016-10-14 12:51
Hi there friends, how is everything, and what you wish for to say about this article,
in my view its truly amazing in favor of me.
Quote
0 #3 Pacheco 2016-11-11 19:11
This is a good post.
However it you should also alert (hoping you know about it) the problems with "auto" and {}-initialization.

:)
Quote
+2 #4 Rainer Grimm 2016-11-12 08:51
Quoting Pacheco:
This is a good post.
However it you should also alert (hoping you know about it) the problems with "auto" and {}-initialization.

:)
Thanks. I will add a few words.
Quote
+3 #5 Niklas 2017-03-28 00:41
Excellent site you've got here.. It�s hard to find high-quality writing like yours these days.
I seriously appreciate individuals like you! Take care!!
Quote
+2 #6 Raquel 2017-04-07 10:53
I constantly spent my half an hour to read this webpage's articles every day along with a mug of coffee.
Quote
+1 #7 Declan 2017-09-18 00:46
Excellent post. I will be going through some oof these issuees as
well..
Quote

Stay Informed about my Mentoring

 

Mentoring

English Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Course: The All-in-One Guide to C++20

Course: Master Software Design Patterns and Architecture in C++

Subscribe to the newsletter (+ pdf bundle)

All tags

Blog archive

Source Code

Visitors

Today 2009

Yesterday 4344

Week 38887

Month 19133

All 12097342

Currently are 156 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments