Reputation: 674
I'm somewhat new to c++ programming. I couldn't find my answer any where on google so hopefully it can be answered here.
is there a difference between the following
unsigned int counter{ 1 };
or
unsigned int counter = 1;
the book uses the first option and its confusing to me because it doesn't explain the difference. below is the following code from the book i'm following.
#include <iostream>
#include <iomanip>
#include <cstdlib> // contains function prototype for rand()
using namespace std;
int main()
{
for (unsigned int counter{ 1 }; counter <= 20; ++counter) {
cout << setw(10) << (1 + rand() % 6);
// if counter is divisible by 5, start a new line of output
if (counter % 5 == 0) {
cout << endl;
}
}
}
Upvotes: 6
Views: 1358
Reputation: 139
unsigned int counter = 1 ;
This style of initialization is inherited from C language.
unsigned int counter {1} ;
This style of initialization is of C++.
The difference is if you provide a wrong value while using C++ style initialization for example:
unsigned int counter {-1} ;
This will give error (use -std=c++11
to compile it)
But this will not give any error.
unsigned int counter = -1 ;
Upvotes: 1
Reputation: 310990
Consider the following demonstrative program.
#include <iostream>
struct A
{
int x;
explicit A( int x = 0 ) : x( x ) {}
};
int main()
{
A a1 { 10 };
std::cout << "a1.x = " << a1.x << '\n';
// A a2 = { 10 };
}
In this declaration
A a1 { 10 };
there is used the direct initialization.
And in the commented declaration
// A a2 = { 10 };
that can be also rewritten like
// A a2 = 10;
there is used the copy-initialization. But the constructor declared with the specifier explicit
. So the compiler will issue an error. That is it is unable to convert the integer object 10
to the type of A
implicitly.
You could write instead
A a2 = A{ 10 };
That is calling the constructor explicitly.
Of course for fundamental types there is no difference because neither constructor is applied except that narrowing conversion is not allowed when the braced initialization is used as for example
int x { 1.0 };
There is a big difference when the type specifier is the placeholder auto
.
For example
auto x = 10;
x
has the type int
.
auto x { 10 };
x
again has the type int
.
auto x = { 10 };
Now x
has the type std::initializer_list<int>
.
For example you could rewrite your loop
for (unsigned int counter{ 1 }; counter <= 20; ++counter) {
the following way
for ( auto counter{ 1u }; counter <= 20; ++counter) {
but you may not write
for ( auto counter = { 1u }; counter <= 20; ++counter) {
because in this case the type of the variable counter
is std::initializer_list<unsigned int>
.
So in general you have the following forms of initializations
T x = value;
T x = { value };
T x( value );
T x { value };
For example
#include <iostream>
int main()
{
int x1 = 1;
std::cout << "x1 = " << x1 << '\n';
int x2 = ( 2 );
std::cout << "x2 = " << x2 << '\n';
int x3( 3 );
std::cout << "x3 = " << x3 << '\n';
int x4{ 4 };
std::cout << "x4 = " << x4 << '\n';
}
The program output is
x1 = 1
x2 = 2
x3 = 3
x4 = 4
But there is one more situation when instead of T()
you should use T{}
as an initializer. It is when template functions are used.
Consider the following demonstrative program
#include <iostream>
template <class>
void f()
{
std::cout << "f<T>() is called\n";
}
template <int>
void f()
{
std::cout << "f<int>() is called\n";
}
int main()
{
f<int()>();
f<int{}>();
}
Its output is
f<T>() is called
f<int>() is called
The construction int()
used as a template argument specifiers the type template argument int
while the construction int{}
used as a template argument specifiers a non-type template argument of the type int
equal to 0
.
Upvotes: 1
Reputation: 61
Adding to the other explanations above. I would use the first option(unsigned int counter{ 1 };) to initialize a list of values for a variable and for a single value, I would prefer to use the second option(unsigned int counter = 1;)
Hope this helps.
Upvotes: 1
Reputation: 9715
Yes, they are two different types of initialization in C++.
The first one, i.e., unsigned int counter{ 1 };
is a direct initialization.
Whereas, the second one, i.e., unsigned int counter = 1;
, is a copy initialization.
For all the details you can directly refer to the documentation.
However, I can emphasize:
Copy-initialization is less permissive than direct-initialization: explicit constructors are not converting constructors and are not considered for copy-initialization.
Initialization references here
For unsigned int
type (such in your case), there are no real differences between the two initializations.
Note
The usage of curly braces in the first statement (unsigned int counter{ 1 }
) provides an additional constraint:
Otherwise (if T is not a class type), if the braced-init-list has only one element [...], T is direct-initialized [...], except that narrowing conversions are not allowed.
In other words, the usage of curly braces in the initialization does not allow data looseness.
That is:
unsigned int counter{ 12.3 }; // error!!!
won't compile because you are trying to initialize an integer with a floating-point value.
Note this is a "property" of curly braces in the initialization. It is not strictly related to the initialization type.
In fact, you can also write:
unsigned int counter = { 12.3 }; // error!
which is, instead, a copy initialization, but having curly braces does not allows narrowing conversions.
Upvotes: 5