Constructor of type int - c++

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

Related

Function style casting using the `new T()` operator in C++

Here is an example of a simple function style casting done by int(a):
float a = 5.0;
int b = int(a);
More info from cpprefrenece:
The functional cast expression consists of a simple type specifier or a typedef specifier followed by a single expression in parentheses.
I have 2 questions:
1) would using the new operator still count as a functional cast?
int* b = new int(a);
2) Assuming test is a class, then test t = test(1); is a function style casting to test but test t = test(1, 2); isn't because it has more than 1 expression in parenthesis?
would using the new operator still count as a functional cast?
No, the use of the new operator(like you used in your example) is not a use case of functional cast.
test t = test(1, 2); isn't because it has more than 1 expression in parenthesis?
Both test t = test(1); and test t = test(1,2); are copy initializations. Now, the subexpression test(1) is indeed a functional cast where the appropriate test constructor will be used. While the subexpression test(1, 2) is not as it has more than a single expression inside parenthesis.
1) New expression
A new-expression is a special case of... a new-expression. Nothing less, nothing more. It results in creation of object of given type in dynamic storage and , for class-types, in a call to constructor with given argument list. For trivial types new-expression provides an initializer.
A new-expression isn't a cast, albeit initializing parameters from argument list given in parenthesis may involve implicit casts. If returned result of new-expression wasn't used, the created object would continue to exist. And unless there is a curious contingency involved, it would not be correctly freed.
A functional cast would produce an xvalue, an object which would expire at end of enclosing expression.
C++ parser by design is a "greedy" parser. It doesn't try to single out every token first, it's a complex algorithm to match statements to whole patterns, as longer as possible, appropriate for current context (and context may change in result). The "greedy" nature becomes obvious in case of some ill-formed or ambiguous code. As a rule, if something can be parsed wrong, it will be parsed wrong, but not until whole statement would be analyzed.
Speaking of functional cast, typename(name) syntax may appear in declarations of variables or types, which result in following being a legal declaration:
int foo ( int (a) )
{
return a;
}
It's because since times of C we can declare some eldritch array of pointers as void (*(*f[])())(), which declares f as array of pointers to function returning a pointer to function returning void.
In result, initializing a variable with a functional cast may create an ambiguous code:
float fvar = 1.0f;
double dvar ( int(fvar) );
It declares a double(int) function named dvar! You wouldn't spot it, until you try assign to it:
auto v = dvar; // v is a pointer to function.
dvar = 4; // error
The declaration of dvar as whole matches BOTH a function declaration and a variable declaration. In this case compiler MUST choose wrongly, but diagnostics are optional. It's exacerbated by fact that C and C++ are allowing variable identifiers to match type names.
2) Initialization of object
Yes, the expression test(1) is a functional cast even if test is a class. By definition it results in considering an existing constructor to be called.
class test {
public:
test(int arg): b(arg) {}
protected:
int b;
};
Here constructor test(int) is called a conversion constructor as it can take exactly one parameter and its usage permits use of type-id test in functional cast - from int or int-compatible type. Constructors with more than one parameter without default value do not bear this name. For class test , te expression test(1,2) is ill-formed.
In fact, unless such constructor qualified as explicit, it would allow an implicit conversion:
struct test {
test(int a) {std::cout << "int " << a << std::endl;}
explicit test (float a) {std::cout << "float " << a << std::endl;}
};
int main()
{
test b = 1; // calls (int) constructor
test c = 2.0f; // calls (int) constructor
test d = test(3.0f); // function cast calls (float) constructor
}
P.S. C++11 allowed to escape functional cast syntax for initialization of class-type object. For above class it would be test{1}. But it also can be an aggregate initialization, if test would be trivial:
struct test {
int b;
};
test t = test{1};
New Operator
Yes. From the cppreference page on the new keyword
The object created by a new-expression is initialized according to the following rules:
For non-array type, ...
If initializer is a parenthesized list of arguments, the object is direct-initialized.
And if we check out the page on direct initialization, we find that syntax (3) on that page is
T ( other )
T ( arg1, arg2, ... )
initialization ... by functional cast or with a parenthesized expression list
So new is defined to perform direct initialization, and direct initialization is defined to perform a functional cast when necessary. There's more going on with regard to allocation in the background, but at some point down the line a functional cast may get performed.
More than 1 Expression
In regards to your second question, a "cast" is a conversion from one type to another. An initialization with one argument can be viewed as a cast, from the argument type T to the result type S. It makes no sense to think of test(1, 2) as a conversion from anything, since it takes two arguments and produces one value.

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.

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

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.

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};
}

How does constructor conversion work in C++?

How does constructor conversion work?
#include <iostream>
using namespace::std;
class One {
public:
One() { cout<<"One"<<endl;}
};
class Two {
public:
Two(const One&) {cout<<"Two(const One&)"<<endl;}
};
void f(Two) {cout<<"f(Two)"<<endl;}
int main() {
One one;
f(one);
}
produces the output
One
Two(const One&)
f(Two)
Any constructor that can be called with a single argument is considered an implicit conversion constructor. This includes simple 1-argument cases, and usage of default arguments.
This conversion is considered in any context that wants X and provided Y, and Y has such implicit conversion possibility. Note that a plenty of other, built-in conversions also play as a mix (like adjusting const-ness, integral and fp promotions, conversions, etc.) The rule is that at most one "user defined" implicit conversion is allowed in the mix.
In some cases it may be quite surprising, so the general advice is to make any such ctors explicit. That keyword makes the conversion possible but not implicitly: you must use T() syntax to force it.
As an example consider std::vector that has a ctor taking size_t, setting the initial size. It is explicit -- otherwise your foo(vector<double> const& ) function could be mistakenly called with foo(42).
It's right result. Since constructor is not explicit - implicit conversion works (here One is implicitly converted to Two).
one is created, then when passed to f converted to Two.
What the Two(const One&) {cout<<"Two(const One&)"<<endl;} constructor means is that you're allowed to construct a Two value at any time - implicitly - from a One. When you call f(one) it wants a Two parameter, it's given a One, so the compiler puts 2 and 2 together and says "I'll make a temporary Two from the One and complete the call to f()"... everyone will be happy. Hurray!
Compiler has to create copy of Two instance on stack. When you call f() with argument which is object of class One (or any other) compiler looks to definition of class Two and tries to find constructor which takes One(or any other) object(or reference) as an argument. When such constructor has been found it constructs object using it. It's called implicit because compiler do it without your interference.
class Foo {
public:
Foo(int number) {cout<<"Foo(int number)"<<endl;}
};
void f(Foo) {cout<<"f(Foo)"<<endl;}
int main() {
f(24);
} ///:~
Output will be:
Foo(int number)
f(Foo)