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?
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?
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
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
todouble
orfloat
, or fromdouble
tofloat
, 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), orfrom 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.
The first is the copy initialization, while the second is list initialization.
But, usually copy initialization is less used. Because, if you're doing it by passing objects of user defined types, it just causes bitcopy & hence may not produce intended results if the user defined class uses pointers.
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).