What is the correct way to initialize a variable in C ++

I have the following code:

bool c (a == b); 

and

 bool c {a == b}; 

where a and b are some variables of the same type.

I want to know what is the difference in the two previous initializations and which one should I choose under what conditions? Any help would be appreciated.

+4
source share
3 answers

Both forms are direct initialization .

Using curly braces {} for initialization checks for narrowing conversions and generates an error if such a conversion occurs. Unlike () . ( gcc is wrong in this case and needs the -Werror=narrowing compiler option to generate a narrowing error.)

Another use of braces {} for uniform initialization is to initialize both types with and without constructors using the same syntax, for example:

 template<class T, class... Args> T create(Args&&... args) { T value{std::forward<Args>(args)...}; // <--- uniform initialization + perfect forwarding return value; } struct X { int a, b; }; struct Y { Y(int, int, int); }; int main() { auto x = create<X>(1, 2); // POD auto y = create<Y>(1, 2, 3); // A class with a constructor. auto z = create<int>(1); // built-in type } 

The only drawback to using curly braces {} for initialization is its interaction with the auto keyword. auto displays {} as std::initializer_list , which is a known issue, see "Auto and copied start lists . "

+9
source

The first is the direct initialization of the C ++ 03 style. The second is the direct initialization of the C ++ 11 style, it additionally checks for narrowing conversions. Herb Sutter recommends the following in the new code:

 auto c = <expression>; 

or if you want to commit a specific type of T:

 auto c = T{<expression>}; 

One known drawback with curly braces is when T is some class with an overloaded constructor, where one constructor gets std :: initializer_list as a parameter, std :: vector for example:

 auto v = std::vector<int>{10}; // create vector<int> with one element = 10 auto v = std::vector<int>(10); // create vector<int> with 10 integer elements 
+2
source

Now we have five forms of initialization. They are

 T x = expression; T x = ( expression ); T x ( expression ); T x = { expression }; T x { expression }; 

Each form has its own characteristics. :)

For example, suppose you have the following declarations in the global namespace

 int x; void f( int x ) { ::x = x; } int g() { return x ; } long h() { return x; } 

then basically you can write

 int main() { int x ( g() ); } 

This code will be compiled successfully.

However, the programmer mistakenly made a typo

 int main() { int x; ( g() ); ^^ } 

Oops! This code also compiles successfully. :)

But if the programmer writes

 int main() { int x = ( g() ); } 

and then create a typo

 int main() { int x; = ( g() ); ^^ } 

then in this case the code will not compile.

Suppose the programmer decided to first set a new value for global variabel x before initializing the local variable.

So he wrote

 int main() { int x ( f( 10 ), g() ); } 

But this code does not compile!

Insert equal sign

 int main() { int x = ( f( 10 ), g() ); } 

Now the code compiles successfully!

What about braces?

Neither this code

 int main() { int x { f( 10 ), g() }; } 

and this code

 int main() { int x = { f( 10 ), g() }; } 

compiles!)

Now the programmer decided to use the h () function, he wrote

 int main() { int x ( h() ); } 

and his code compiles successfully. But after some time he decided to use braces

 int main() { int x { h() }; } 

Oops! Its compiler gives an error message

error: a non-constant expression cannot be narrowed from type 'long' to 'int' in the initialization list

The program decided to use an auto type specifier. He tried two approaches

 int main() { auto x { 10 }; x = 20; } 

and

 int main() { auto x = { 10 }; x = 20; } 

and ... some compilers did not compile the first program, but did not compile the second program, and some compilers did not compile both programs. :)

What about using decltype ?

For example, a programmer wrote

 int main() { int a[] = { 1, 2 }; decltype( auto ) b = a; } 

And its compiler throws an error!

But when the programmer enclosed a in parentheses like this

 int main() { int a[] = { 1, 2 }; decltype( auto ) b = ( a ); } 

The code compiled successfully! :)

Now the programmer decided to study OOP. He wrote a simple class

 struct Int { Int( int x = 0 ) : x( x ) {} int x; }; int main() { Int x = { 10 }; } 

and his code compiles successfully. But pogrammer knew that an explicit function specifier existed, and he decided to use it

 struct Int { explicit Int( int x = 0 ) : x( x ) {} int x; }; int main() { Int x = { 10 }; } 

Oops! Its compiler issued an error

 error: chosen constructor is explicit in copy-initialization 

The programmer decided to remove the destination sign

 struct Int { explicit Int( int x = 0 ) : x( x ) {} int x; }; int main() { Int x { 10 }; } 

and his code compiled successfully! :)

+1
source

All Articles