The following code can pass compiling and will print 0 on the console. I saw similar code in STL. Does type int in C++ have a constructor? Is int() a call of some defined function?
int main()
{
int a = int();
cout << a << endl;
return 0;
}
In this context,
int a = int(); // 1)
it value-initializes a, so that it holds value 0. This syntax does not require the presence of a constructor for built-in types such as int.
Note that this form is necessary because the following is parsed as a function declaration, rather than an initialization:
int a(); // 2) function a() returns an int
In C++11 you can achieve value initialization with a more intuitive syntax:
int a{}; // 3)
Edit in this particular case, there is little benefit from using 1) or 3) over
int a = 0;
but consider
template <typename T>
void reset(T& in) { in = T(); }
then
int i = 42;
reset(i); // i = int()
first, we start with this syntax:
type variableName = type();
this syntax is called value initialization of a variableName, or in other word we say a variableName is zero initialized.
But, what is the meaning of the value initialization.
if the type of a variableName is a built-in/scalar type like (int, char, ...),
value initialization mean that a variableName is initialized with the value zero.
and if the type is a complex type like (classes, structs, ...) mean that a variableName is initialized by calling its default constructor.
int() is the constructor of class int. It will initialise your variable a to the default value of an integer, i.e. 0.
Even if you don't call the constructor explicitly, the default constructor, i.e. int() , is implicitly called to initialise the variable.
Otherwise there will be a garbage value in the variable.
Related
The following code can pass compiling and will print 0 on the console. I saw similar code in STL. Does type int in C++ have a constructor? Is int() a call of some defined function?
int main()
{
int a = int();
cout << a << endl;
return 0;
}
In this context,
int a = int(); // 1)
it value-initializes a, so that it holds value 0. This syntax does not require the presence of a constructor for built-in types such as int.
Note that this form is necessary because the following is parsed as a function declaration, rather than an initialization:
int a(); // 2) function a() returns an int
In C++11 you can achieve value initialization with a more intuitive syntax:
int a{}; // 3)
Edit in this particular case, there is little benefit from using 1) or 3) over
int a = 0;
but consider
template <typename T>
void reset(T& in) { in = T(); }
then
int i = 42;
reset(i); // i = int()
first, we start with this syntax:
type variableName = type();
this syntax is called value initialization of a variableName, or in other word we say a variableName is zero initialized.
But, what is the meaning of the value initialization.
if the type of a variableName is a built-in/scalar type like (int, char, ...),
value initialization mean that a variableName is initialized with the value zero.
and if the type is a complex type like (classes, structs, ...) mean that a variableName is initialized by calling its default constructor.
int() is the constructor of class int. It will initialise your variable a to the default value of an integer, i.e. 0.
Even if you don't call the constructor explicitly, the default constructor, i.e. int() , is implicitly called to initialise the variable.
Otherwise there will be a garbage value in the variable.
What is the "operator int" function below? What does it do?
class INT
{
int a;
public:
INT(int ix = 0)
{
a = ix;
}
/* Starting here: */
operator int()
{
return a;
}
/* End */
INT operator ++(int)
{
return a++;
}
};
The bolded code is a conversion operator. (AKA cast operator)
It gives you a way to convert from your custom INT type to another type (in this case, int) without having to call a special conversion function explicitly.
For example, with the convert operator, this code will compile:
INT i(1234);
int i_2 = i; // this will implicitly call INT::operator int()
Without the convert operator, the above code won't compile, and you would have to do something else to go from an INT to an int, such as:
INT i(1234);
int i_2 = i.a; // this wont compile because a is private
operator int() is a conversion operator, which allows this class to be used in place of an int. If an object of this type is used in a place where an int (or other numerical type) is expected, then this code will be used to get a value of the correct type.
For example:
int i(1);
INT I(2); // Initialised with constructor; I.a == 2
i = I; // I is converted to an int using `operator int()`, returning 2.
First things first:
$12.3.1/1 - "A constructor declared
without the function-specifier
explicit specifies a conversion from
the types of its parameters to the
type of its class. Such a constructor
is called a converting constructor."
In your example, INT is a User Defined class that has a converting constructor from 'int'.
Therefore the following code is well-formed:
INT i(1024); // direct initialization syntax
This means that you can get an INT object from an integer. However what does one do, if the INT object has to be converted back to an integer? Transitivity?
One can say that the class INT can provide a member function to return the encapsulated integer member
int x = i.geta();
This however is not very intuitive and is not a standardized approach. Also it is not intuitive when it comes to how built-in types work in such situations.
int z = 0;
int y1 = z; // copy initialization or
int y2(z); // direct initialization
double d = (int )z; // explicit cast
Therefor the Standard allows for such standardization and intuitiveness of converting User Defined Types by saying:
$12.3/2 - "A member function of a
class X having no parameters with a
name of the form [...]
operator conversion-type-id
[...]specifies a conversion from X to the
type specified by the
conversion-type-id. Such functions are
called conversion functions. No return
type can be specified. If a conversion
function is a member function, the
type of the conversion function
(8.3.5) is “function taking no
parameter returning
conversion-type-id”.
This makes all of the following well-formed and retains harmony with the way built-in types work is
int y1 = i; // copy initialization or
int y2(i); // direct initialization
double d = (int )i; // explicit cast
It looks like it make an INT class which behaves a little like the regular int, just that some other operators are not yet defined.
Is this a homework problem?
Seems like it's a question from a classroom, so I'll invite you to check the documentation on how to create a class.
class Foo
{
public
Foo() {} // Constructor
Foo operator++ {} // Operation ++ on foo like:
// Foo foo;
// foo++;
};
I am writing a generic function like below.
template<class Iterator, class T>
void foo(Iterator first, Iterator last) {
T a;
cout << a << endl;
// do something with iterators
}
typedef vector<double>::iterator DblPtr;
vector<double> values;
foo< DblPtr, int>();
This functions prints out an undefined value for variable a, while if I change the initialization into
///
T a = T()
cout << a << endl;
// do something with iterators
I can see that the initialized value is 0 as I am expecting.
If I call T a the variable is initialized with the default value, but if i call T a = T() I believe that due to optimization the copy constructor should be called with the value of T() that is still the default one.
I cannot understand what is the difference behind these 2 lines and the reason why this happens?
First of all, default initiaization of built-in types such as int leaves them uninitialized. Value initialization leaves them zero-initialized. As for your example
This is a default initialization:
T a;
This is a value initialization, using copy initialization:
T a = T();
You are right that copies can be elided here, so this has the effect of creating a single value-initialized T object. However, it does require that T be copyable or move-copyable. This is the case with built-in types, but it is a restriction to bear in mind.
The copy initialization syntax is required because this is a function declaration:
T a();
but C++11 allows you to value-initialize like this:
T a{};
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
Normally one would declare/allocate a struct on the stack with:
STRUCTTYPE varname;
What does this syntax mean in C (or is this C++ only, or perhaps specific to VC++)?
STRUCTTYPE varname = {0};
where STRUCTTYPE is the name of a stuct type, like RECT or something. This code compiles and it seems to just zero out all the bytes of the struct but I'd like to know for sure if anyone has a reference. Also, is there a name for this construct?
This is aggregate initialization and is both valid C and valid C++.
C++ additionally allows you to omit all initializers (e.g. the zero), but for both languages, objects without an initializer are value-initialized or zero-initialized:
// C++ code:
struct A {
int n;
std::string s;
double f;
};
A a = {}; // This is the same as = {0, std::string(), 0.0}; with the
// caveat that the default constructor is used instead of a temporary
// then copy construction.
// C does not have constructors, of course, and zero-initializes for
// any unspecified initializer. (Zero-initialization and value-
// initialization are identical in C++ for types with trivial ctors.)
In C, the initializer {0} is valid for initializing any variable of any type to all-zero-values. In C99, this also allows you to assign "zero" to any modifiable lvalue of any type using compound literal syntax:
type foo;
/* ... */
foo = (type){0};
Unfortunately some compilers will give you warnings for having the "wrong number" of braces around an initializer if the type is a basic type (e.g. int x = {0};) or a nested structure/array type (e.g. struct { int i[2]; } x = {0};). I would consider such warnings harmful and turn them off.