Semantic difference in C++, defining a constant data instance - c++

Do the following four different syntax do the same thing when initializing a constant data member, of type int for example, in C++ 11? If not, what is the difference?
{
const int a = 5; //usual initialization, "=" is not assignment operator here it is an initialization operator.
}
{
const int a(5); //calling the constructor function directly
}
{
const int a = {5}; //similar to initializing an array
}
{
const int a{5}; //it should work, but visual studio does not recognizing it
}
Why is the fourth one not recognized by Visual Studio as a valid statement?

They are all valid and the same in Visual Studio 2013 (the last one is not valid in VS2012 as #remyabel suggested).
The two {...} syntaxes can differ from the others in what constructor is called for a type, but the type int uses no constructor.
They will differ when constructing a class that accepts a std::initializer_list<T>.
Take, for example, this constructor that has - in some form - always been a part of std::vector
explicit vector( size_type count ... );
And this one that was added in C++11
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );
Here, vector<int>(5) will call the first constructor and make a vector size 5.
And vector<int>{5} will call the second and make a vector of a single 5.

In C++03 these are equivalent
const int a = 3;
const int a(3);
In C++11 the uniform initialization syntax was introduced and thus
const int a{3};
const int a = {3};
are allowed and are equivalent. However, the first two and the second two are NOT equivalent in all cases. {} doesn't allow narrowing. For example
int abc = {12.3f};
int xyz(12.3f);
Here's what GCC says
error: type 'float' cannot be narrowed to 'int' in
initializer list [-Wc++11-narrowing]
int abc = {12.3f};
^~~~~
warning: implicit conversion from 'float' to 'int'
changes value from 12.3 to 12 [-Wliteral-conversion]
int abc = {12.3f};
~^~~~~
So the former begot an error, while the latter, just a warning.
Caveats in the uniform initialization syntax: If a was an object of a type accepting std::initializer_list, then const MyClass a = { 1 } would mean you're using that constructor and not the constructor taking a single int even if it was available (explained in Drew's anwer); If you want to choose the other constructor, then you've to use the () syntax. If a was an array, then you're using aggregate initialization.
See here for various initialization options available in C++.

Visual Studio 2012 doesn't support this syntax. It is however implemented in VS2013. The documentation for initializers in the VS2012 tab doesn't describe any way of using direct initialization with braces (aka,direct-list-initialization). The following is MSVC's documentation on valid initializer syntax, it doesn't necessarily reflect what's valid from a language lawyer point of view.
Declarators can specify the initial value for objects. The only way to
specify a value for objects of const type is in the declarator. The
part of the declarator that specifies this initial value is called the
initializer. There are two fundamental types of initializers:
Initializers invoked using the equal-sign syntax, including aggregate initializers:
= expression
= { expression-list }
= { { expression-list}, {expression-list}, . . . }
Initializers invoked using function-style syntax:
( expression )

Coding style is ultimately subjective, and it is highly unlikely that substantial performance benefits will come from it. But here's what I would say that you gain from liberal use of uniform initialization:
All 4 statements are valid and they are the same.
const int a = 5; -> Anyways, is the normal initialization syntax.
No need of explanation.!
const int a(5); -> function type initialization
const int a = {5}; -> Array type initialization
const int a{5}; -> It is not allowed in Visual Studio 2012, But, Initializer list support has been added in Visual Studio 2013. Hence const int a{5} , compiles fine with out any issues in VS2013.
But,
The only real power you give up is narrowing. You cannot initialize a smaller value with a larger one with uniform initialization.
int val{5.5};
That will not compile. You can do that with old-fashioned initialization, but not uniform initialization.

Related

Type safety during assignment vs initialization

One of the stated advantages of initializer list syntax is that it improves type safety by prohibiting narrowing conversions:
int x {7.9}; // error: narrowing
int y = 7.9; // OK: y becomes 7. Hope for a compiler warning
However, AFAIK there is no way to enforce the same check in a subsequent assignment:
int z {7};
z = 7.9; // allows narrowing, and no other syntax available
Why is type safety during initialization given greater attention by the language design than type safety during assignment? Is narrowing in assignments less likely to cause bugs and/or harder to detect?
If x is an int variable, then
x = 7.9;
must continue working in C++11 and later for the reason of backward compatibility. This is the case even if x was brace-initialized. A brace-initialized int variable has the same type as a non-brace-initialized int variable. If you passed x by reference to a function,
void f(int& r);
f(x);
then in the body of f there would be no way to "tell" whether the object had been brace-initialized, so the language cannot apply different rules to it.
You can prevent narrowing conversions yourself by doing this:
x = {7.9}; // error
You could also try to take advantage of the type system by creating an int "wrapper" type that disallowed narrowing assignments:
struct safe_int {
template <class T> safe_int(T&& x) : value{std::forward<T>(x)} {}
template <class T> safe_int& operator=(T&& x) {
value = {std::forward<T>(x)}; return *this;
}
operator int() const { return value; }
int value;
};
Unfortunately this class cannot be made to behave like an actual int object under all circumstances.
Why is type safety during initialization given greater attention by
the language design than type safety during assignment?
No that's not the reason here, it's the list initialization that's giving you the error, for example, this would error too:
int x = {7.8};
And that is because narrowing is not allowed in list initialization, as per [dcl.init]:
If the initializer-clause is an expression and a narrowing conversion
is required to convert the expression, the program is ill-formed.
{} prevent convertion type e.g double to int
but
() can do this, only can display warning about conversion
you can to write like this
int z(7.9) // == 7
you can use brackets when you are sure, that in class don't exist constructor with std::initializer_list, because he would be execute or you can delete that constructor.

which one should i use and why: {} vs = in c++

I was watching MVA's(Microsoft Visual Academy's) tutorials and I came across these two operators i.e. {} and = to pass in the value to variables. I have done C programming so I am pretty much aware of the assignment operator =. But {} is not in any language I did so far.
Kate is teaching the C++ course so she told that {} is used for copying.
But I was using the operator {} in the class below and it shows some error when I try to do this:
this->_width{new_width};
whereas below one works:
this->_width = new_width;
Why so? I am also using {} to pass values in constructor but then they work perfectly. Only Problem is with member fucntions.
class Rectangle
{
public:
void resize(int new_height, int new_width) { this->_width{new_width ; this->_height{new_height}; //member function
Rectangle(): _width{} , height{} {} //constructor
private:
int _width;
int _height;
};
{} can be used to initialise variables in C++11 in the same way that they are used to initialise arrays and structures in C.
This has been introduced primarily to provide consistency in language syntax (initialising with {} will work in all contexts, whereas initialising using the assignment operator or () will work in specific contexts.
There is a further advantage to list initialisation in that it prevents narrowing - i.e. it prevents you from providing an integer when a double is required, or a short when an integer is required. In this way it can help to reduce bugs.
Note that {} cannot be used to pass values to a function - only to construct new objects.
This page is also worth reading
Using {} is called uniform initialization in this context. It was introduced mainly for two reasons.
First, as the name indicates, initialization is uniform, that is it looks and works the same for single objects, arrays, containers that accept initializer lists, etc.
Second, and equally important, it is impossible to get a most vexing parse using curly braces, which is quite possible unintentionally otherwise:
A a(); // What does this do? What was probably intended?
B b{}; // And what does this do?
Also, as a bonus (kudos to #Richard Hodges), you avoid narrowing conversions using uniform initialization.
To literally answer the question "which one should I use?", you should preferrably use {} as it has only advantages, and no disadvantages (plus, Bjarne Stroustrup recommends using it).
Non-static data members may be initialized in one of two ways:
1) In the member initializer list of the constructor.
struct S {
int n;
std::string s;
S() : n(7) // direct-initializes n, default-initializes s
{ }
};
2) Through a brace-or-equal initializer, which is simply an initializer included in the member declaration, which is used if the member is omitted in the member initializer list
struct S {
int n = 7;
std::string s{'a', 'b', 'c'};
S() // copy-initializes n, list-initializes s
{ }
};
You may use brace initializers in the member declaration.
Also, from the standard, N4296, § 9.2, paragraph 4:
A brace-or-equal-initializer shall appear only in the declaration of
a data member.

Is there a difference between assigning a value to a variable using the equal operator or using curly braces?

I saw a code where a programmer used curly braces to initialize a variable
int var{ 5 };
instead of using the assignment operator
int var = 5;
I know assigning a value to lhs variable using curly braces is a C++11 syntax. Is there any difference between using the two?
Thank you for replies.
They are different kinds of initialization:
T a{b}; // list initialization
T a = b; // copy initialization
T a(b); // direct initialization
There is no difference for ints but there can definitely be differences for other types. For instance, copy initialization might fail if your constructor is explicit, whereas the other two would succeed. List initialization disallows narrowing conversions, but for the other two those are fine.
As far as I know, there is no difference in the two for integers. The {} syntax was made to(however, not limited to, because it is also used for initializer_list) prevent programmers from triggering http://en.wikipedia.org/wiki/Most_vexing_parse, and so instead of std::vector<int> v() to initialize v you write std::vector<int> v{};.
The {} has different behaviours depending on the usage, it can be a call to constructor, a initializer list and even a list of values to initialize members of user-defined class in order of definition.
Example of the last:
class Q{
public:
int a;
int b;
float f;
};
int main()
{
Q q{2, 5, 3.25f};
}

Compilation fails when passing array with missing initializers as argument

When I try to compile
template<int dim>
struct Foo
{
Foo(const int (&i)[dim]) {}
};
int main()
{
Foo<2> f = Foo<2>((int[2]){0}); // line 9
return 0;
}
I get the compilation error
test.cpp:9:31: error: no matching function for call to ‘Foo<2>::Foo(int [1])’
Apparently, the argument I pass to the constructor is regarded as an int[1]. Why isn't it regarded as an int[2] (which could then be casted to a const reference as expected by the constructor)? Shouldn't the missing elements be value-initialized according to 8.5.1 (7)?
After all, replacing line 9 with
int arg[2] = {0};
Foo<2> f = Foo<2>(arg);
lets me compile the program. Additionally, when I try to pass (const int [2]){0, 0, 0} to the constructor, I get the error message too many initializers for ‘const int [2]’, so apparently, the compiler is trying to construct a const int[2].
Somebody please shed some light on this unintuitive behavior.
The construct (int[2]){0} is a C99 compound literal, which is not part of C++. How particular compilers interpret in the context of C++ is anyone's guess (or a matter of examining the source code).
PS. OK, it seems that gcc 4.7/gcc 4.8/clang-3.1 handle it quite sensibly - the type of the compound literal is the same as the C99 standard specifies it.
I guess the OP compiler is a bit older.

Constructor of type int

Considering the cost, are these cases the same?
// case 1
int a = 5;
// case 2
int a (5);
// case 3
int a;
a = 5
The three syntaxes are different, bear with me while I use a user defined type instead of int, I will go back to int later.
T a(5); // Direct initialization
T b = 5; // Implicit conversion (5->tmp) + copy-initialization
T c; c = 5; // Default initialization + assignment
In the first case the object a is constructed by means of a constructor that takes an int or a type that can be implicitly converted from int.
struct T {
T( int ); // T a(5) will call this directly
};
In the second case, a temporary object of type T is created by an implicit conversion from int, and then that temporary is used to copy construct b. The compiler is allowed to optimize the code away and perform just the implicit conversion in place of the final object (instead of using it to create the temporary. But all restrictions have to be verified:
class T {
T( T const & );
public:
explicit implicit T( int );
};
int main() {
T b = 5; // Error 1: No implicit conversion from int to T.
// Fix: remove the `explicit` from the constructor
// Error 2: Copy constructor is not accessible
}
The third case is default construction followed by assignment. The requirements on the type are that it can be default constructed (there is a constructor with no arguments, or there is no user defined constructor at all and the compiler will implicitly define it). The type must be assignable from int or there must be an implicit conversion from int to a type U that can be assigned to T. As you see, the requirements for the type in the tree cases differ.
Besides the semantics of the different operations, there is other important difference, not all of them can be used in all of the contexts. In particular, in an initialization list in a class you cannot use the implicit convert + copy initialize version, and you can only have the first half of default construct + assign.
// OK // error // ok but different
struct test { struct test { struct test {
T x; T x; T x;
test(int v) : x(v) {} test(int v) : x=5 {} test( int v ) {
x = v;
}
In the first case the attribute x is directly initialized with the value v. The second case is a syntax error. The third case first default initializes and then assigns inside the body of the constructor.
Going back to the int example, all of the requirements are met by the type, so there is almost no difference on the code that the compiler generates for the three cases, but still you cannot use the int b = 5; version inside an initializer list to initialize an integer attribute. Moreover, if a class has a member attribute that is a constant integer, then you cannot use the equivalent of int c; c =5; (third column above) as the member attribute becomes const when it enters the constructor block, that is, x = v; above would be trying to modify a constant and the compiler will complain.
As to the cost that each one has, if they can be used at all, they incur the same cost for an int (for any POD type) but not so for user defined types that have a default constructor, in which case T c; c = 5; will incur the cost of default construction followed by the cost of assignment. In the other two cases, the standard explicitly states that the compiler is allowed to generate the exact same code (once the constraints are checked).
First and second are exactly same as both are initialization. Third one is different, as this is assignment. These differences are as per the C++ Standard. However, the compiler can treat all three as same!
For the first two, there will be no difference.
From Standard docs, 8.5.11,
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. A parenthesized initializer can be a list of expressions only when the
entity being initialized has a class type.
The third one is not an initialization but an assignment.
And considering the cost,
In the first two cases, you are creating an integer with a value 5.
In the third case, you are creating an integer with an undefined value and replace it with 5..
If you use an optimizing compiler, they will all compile to the same code. So they all have the same cost.
Yes, they all evaluate to the exact same assembler representation. You can test this e.g. with GCC by writing a dummy function and then producing the assembler output: g++ -S file.cxx -o file.s