Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialization difference with or without Curly braces in C++11

We can initialize the variable in two ways in C++11

One:

int abc = 7; 

Two:

int abc {7}; 

What is the difference between these two methods?

How compiler treats them differently or the way these codes are executed?

like image 445
techfun Avatar asked Jan 15 '14 22:01

techfun


People also ask

Why is brace initialization preferred?

Since C++11 we have uniform brace-init syntax which lets initialize objects using {} instead of () . I have read that as of now, {} is recommended because it disallows narrowing convertions and can be applied to types without any declared constructors.

What is brace initialization?

If a class has non-default constructors, the order in which class members appear in the brace initializer is the order in which the corresponding parameters appear in the constructor, not the order in which the members are declared (as with class_a in the previous example).

Why do we use curly braces in C?

In programming, curly braces (the { and } characters) are used in a variety of ways. In C/C++, they are used to signify the start and end of a series of statements. In the following expression, everything between the { and } are executed if the variable mouseDOWNinText is true. See event loop.

Why initialize with curly braces C++?

The code above shows how curly braces can be used to declare various types of variables and assign values to them. Using curly braces instead of an = sign is one of the many ways to initialize. Using curly braces to initialize a variable also prevents narrowing.


2 Answers

Short version

Initialization via {..} is list-initialization, which prohibits narrowing conversions. For example, if LLONG_MAX is the maximum value of an long long int, and your int cannot represent that:

int x = LLONG_MAX;  // probably accepted with a warning int x {LLONG_MAX};  // error 

Similarly:

long long y = /*something*/;  int x = y;  // accepted, maybe with a warning int x {y};  // error 

Long version

An initialization of the form

T x = a; 

is copy-initialization; an initialization of either form

T x(a); T x{a}; 

is direct-initialization, [dcl.init]/15-16.

[dcl.init]/14 then says:

The form of initialization (using parentheses or =) is generally insignificant, but does matter when the initializer or the entity being initialized has a class type; see below.

So for non-class types, the form of the initialization doesn't matter. However, there's a difference between these two direct-initializations:

T x(a);  // 1 T x{a};  // 2 

and similarly, between these two copy-initializations:

T x = a;    // 1 T x = {a};  // 2 

Namely, the ones with {..} use list-initialization. The {..} is called a braced-init-list.

So, when you compare T x = a; to T x {a};, there are two differences: copy- vs. direct-initialization, and "non-list-" vs. list-initialization. As already mentioned by others and in the quote above, for non-class types T, there's no difference between copy- and direct-init. However, there's a difference between list-init and no list-init. That is, we could as well compare

int x (a); int x {a}; 

List-initialization in this case prohibits narrowing conversions. Narrowing conversions are defined in [dcl.init.list]/7 as:

A narrowing conversion is an implicit conversion

  • from a floating-point type to an integer type, or

  • from long double to double or float, or from double to float, except where the source is a constant expression and the actual value after conversion is within the range of values that can be represented (even if it cannot be represented exactly), or

  • from an integer type or unscoped enumeration type to a floating-point type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type, or

  • from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type.

like image 55
dyp Avatar answered Oct 09 '22 11:10

dyp


While for int the existing replies are complete, I painfully found out, that in some cases, there are other differences between the () and {} initializations.

The keyword is that {} is an initializer list.

One such cases is, the std::string initialization with count copies of a char:

std::string stars(5, '*') 

will initialize stars as *****, but

std::string stars{5, '*'} 

will be read as std::string stars(char(5), '*') and initialize star as * (preceded by an hidden character).

like image 20
a.l.e Avatar answered Oct 09 '22 13:10

a.l.e