I am learning C++ and I am a bit confused about the initialization of int variables.
This code (including the comments) is a copy/paste from Nawaz's answer in this topic Why does C++ require a user-provided default constructor to default-construct a const object?
struct POD
{
int i;
};
POD p1; //uninitialized - but don't worry we can assign some value later on!
p1.i = 10; //assign some value later on!
POD p2 = POD(); //initialized
For p2, I understand that the following is happening:
The default constructor POD() is called to create a temporary POD object. The constructor is not user-defined, so it is implicit. For built-in types like int, the implicit default constructor does nothing (no initialization). Therefore i contains some random stuff.
The copy constructor is called to create p2 using the temporary POD object (whose i is still uninitialized). Therefore the i member of p2 should not be initialized either.
However, the comment says that p2 is initialized!
Any explanation is welcome. Thanks.
For built-in types like int, the implicit default constructor does nothing (no initialization).
This is true but it is also not. Default initialization results in an unitialized object, while value initialization doesn't.
Why are these cases different?
1. C++11, 8.5/11
If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value.
If you use int i; this results in an uninitialized integer!
2. C++11, 8.5/10
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
If you use int i = int(); you have a value-initialized i. Now, what is value-initialized?
3. C++11, 8.5/7
To value-initialize an object of type T means:
[...] (some options where T may be class or array type)
otherwise, the object is zero-initialized.
Ok now we know that int i = int(); means having i=0.
Since your struct is POD, value-initializing it means value-initializing all of its members.
You can have a shortcut on the general behaviour
int i1, i2 = int();
std::cout << i1 << std::endl;
std::cout << i2 << std::endl;
If the memory where i1 resides, isn't zero by any luck you can have the output will probably be
somevalue
0
[As #jogojapan mentioned correctly: Reading from i1 is undefined in first place, so don't do it. You'll most likely observe what I describe here but since the standard doesn't enforce compilers to behave this way i1 may be zero, or brake the expected result in any other strange way.]
Be aware of the following:
Note: Since () is not permitted by the syntax for initializer,
X a();
is not the declaration of a value-initialized object of class X, but the declaration of a function taking no argument and returning an X.
Emphasis on standard quotes are mine.
If class type POD has no user-defined constructor (as is the case in your example), then POD() does not call default constructor. Instead the object is created without using any constructors at all. The compiler performs so called value-initialization of the temporary object. Value-initialization is a self-sufficient method of initialization, which does not necessarily use constructors. Instead, value-initialization of the entire object recursively performs value-initialization of all of its subobjects, one after another. For members of type int value-initialization means zero-initialization.
This is why POD().i is guaranteed to be zero. That zero was not placed there by any constructors. That zero was placed there by value-initialization.
Related
I came upon this interesting answer when our team was dealing with a valgrind warning about unitialized members of a POD in our C++ code:
https://stackoverflow.com/a/5914697/629530
Restating the salient points, consider the following POD structure in C++:
struct C
{
int x;
int y;
};
The following invocations of constructing an object of type C invokes the default constructor and the members are initialized with that default constructor (again, copying the code and comments from Martin York's answer):
C c = C(); // Zero initialize using default constructor
C c{}; // Latest versions accept this syntax.
C* c = new C(); // Zero initialize a dynamically allocated object.
Makes sense. Martin York goes on to point out that the with the following declarations, however, the members of c are not initialized via a constructor and therefore contain undefined data:
C c; // members are random
C* c = new C; // members are random (more officially undefined).
That's interesting. I had used braced-init-list initialization of POD types before, but I didn't realize that C c; would not call the default constructor for a POD type. His answer satisfies the question, but I'd like to know specifically what is instantiated when the latter, non-default constructed c objects are declared. Specifically, the following would be helpful to me:
What is the official name for this non-default initialization of POD types? I'm having trouble googling for this mechanism because I don't know its name.
If the POD type has something less trivial than an int-type, such as a std::string, is the memory for that member also initialized with undefined values? Or is the default constructor for a std::string called for that member?
Update.
Thanks for the input. This has been duplicated to a question with this single answer:
https://stackoverflow.com/a/8860787/629530
According to that answer (and the answers to the question it is duplicated to), a declaration of the form without a parentheses is called "default initialized":
Info *p = new Info; <------- Default Initialization
For default initialization, these points about initialization are made:
To default-initialize an object of type T means:
if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
if T is an array type, each element is default-initialized;
otherwise, the object is zero-initialized.
I might be misunderstanding something, but the struct named C proposed above is a POD type that is not an array. Thus it should be zero initialized? The members are not, however, zero initialized but contain undefined values. How do I reconcile this?
default-initialize an object of type T means:
... otherwise, the object is zero-initialized.
No.
Your first linked answer is correct about C++11 onwards, and this is called default-initialization. It's different to default-construction or value initialization.
The second linked answer was probably correct for C++03, but is wrong for C++11 onwards (even though it was written in 2012). I don't have a copy of the '03 standard to verify, and it was a long time ago.
The effects of default initialization are:
if T is a non-POD (until C++11) class type, the constructors are considered and subjected to overload resolution against the empty argument list. The constructor selected (which is one of the default constructors) is called to provide the initial value for the new object;
if T is an array type, every element of the array is default-initialized;
otherwise, nothing is done: the objects with automatic storage duration (and their subobjects) are initialized to indeterminate values.
Local copy of N4659 agrees with the summary above:
11.6 Initializers [dcl.init]
...
(7.3) Otherwise, no initialization is performed
The section on new-expressions even refers to 11.6 and then says
Note: If no initialization is performed, the object has an indeterminate value.— end note
Current draft has
9.3 Initializers [dcl.init]
...
(7.3) Otherwise, no initialization is performed.
I have a simple struct with an array:
struct A
{
uint32_t arr[size];
};
I have two functions, which create it using default initialization and value initialization:
template<class T>
void testDefault()
{
T* pa = new T; // Default
use(*pa);
delete pa;
}
template<class T>
void testValue()
{
T* pa = new T(); // Value
use(*pa);
delete pa;
}
I'm facing different performance for those functions. The funny thing is that performance differences vary depending on how I declare default constructor of the struct. I have three ways:
struct A
{
uint32_t arr[size];
// Implicit constructor
};
struct B
{
uint32_t arr[size];
B() {}; // Empty constructor
};
struct C
{
uint32_t arr[size];
C() = default; // Defaulted constructor
};
I thought they are all the same from compiler's point of view. Never have been I so wrong. I did run both testDefault() and testValue() several times with structs A, B and C and measured performance. Here is what I have:
Default initialization (implict constructor) done in 880ms
Value initialization (implict constructor) done in 1145ms
Default initialization (empty constructor) done in 867ms
Value initialization (empty constructor) done in 865ms
Default initialization (defaulted constructor) done in 872ms
Value initialization (defaulted constructor) done in 1148ms
Note how performance is clearly worse for both implicit and defaulted constructors. Only empty constructor correctly shows the same performance for both different initialization forms.
I tested this with VC++, gcc and clang. See online demo for gcc. Timings are quite persistent.
What I assume is:
Default and value initializations for UDT are the same thing
All demonstrated ways of defining default constructor are doing the same thing
Default constructor of these structs should leave content of the array in indeterminate state
Since all the compilers exhibit the same timings, it seems like I'm missing something. Can anyone please explain me these timings?
(See also my question Why compilers put zeros into arrays while they do not have to? on the same topic. I give some links to cppreference there.)
Let's look at the definition of value-initialize:
To value-initialize an object of type T means:
if T is a (possibly cv-qualified) class type with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;
if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized [...];
if T is an array type, then each element is value-initialized;
otherwise, the object is zero-initialized.
Also let's review the adjectives in use here for constructors:
user-declared - you declared the constructor
user-provided - you declared the constructor and didn't set it to = default or = delete
default - can be called with no arguments
declared as defaulted - marked = default; or implicitly generated as such
Looking at your classes:
A has a default constructor which is implicitly declared as defaulted, and not user-provided.
C has a default constructor which is user-declared as defaulted, and not user-provided.
So the second bullet point in the definition of value-initialize applies. The object is zero-initialized, meaning the arr is zeroed out.
B has a default constructor which is user-provided.
So the first bullet point of value-initialize applies to B; value-initialization is the same as default-initialization here, and arr is not zeroed out.
Your timings correctly seem to correspond to what is expected: value-initialization of A or C zeroes out arr and the other cases don't.
One of the constructors behaves differently under value initialization. In this version,
B() {};
the array B::arr is not value-initialized when the B is. With the others, it is. Whether this explains the performance difference is another matter.
So, B::arr doesn't get zero-initialized with value initialization, whereas A::arr and C::arr do. All three cases have the same behaviour under default initialization, that is to say, arr gets default-initialized, i.e. no initialization is performed.
I cannot understand the behavior of gcc 4.8.1 or Visual Studio 2015 with respect to default initialization versus value initialization.
It doesn't help that I'm trying to understand the differences between these myself and possibly running into compiler bugs?
My question is: Can someone explain this behavior? And ideally tell me what should be happening.
I have two classes:
class Foo{
int _bar;
public:
void printBar(){ cout << _bar << endl; }
};
class bar{
int ent;
public:
int getEnt(){return ent;}
};
I'm using the following code to test:
int main()
{
Foo foo;
foo.printBar();
Foo().printBar();
bar b;
cout << b.getEnt() << endl;
return 0;
}
On gcc and Visual Studio I get:
134514795
0
0
Now if I change the test code to:
int main()
{
Foo foo;
foo.printBar();
bar b;
cout << b.getEnt() << endl;
return 0;
}
gcc gives me:
0
0
And Visual Studio gives me:
50790236
51005888
Default initialisation, of classes like this without user-defined constructors, does nothing, leaving each trivial member with an indeterminate value.
Value initialisation will zero-initialise each member.
In the first case, you're printing:
the indeterminate value of a default-initialised Foo foo;
the zero value of a value-initialised Foo()
the indeterminate value of a default-initialised bar b;
The third one happens to be zero; perhaps because it reuses the storage of the temporary value-initialised Foo.
In the second case, you're printing the indeterminate values of two default-initialised objects. Coincidentally, they have zero values in one case but not the other.
Both programs have undefined behaviour, since they use uninitialised values.
The logic is quite simple:
Default initialization of a class just default initializes all members.
Default initialization of built-in types leaves member uninitialized.
Accessing an uninitialized object yields undefined behavior.
Undefined behavior can do anything it wants.
Both compilers provide "correct" results. Note that causing nasal demons to be emitted would also be correct.
Foo foo;
This default-initializes foo, and since Foo's default constructor is trivial, it effectively doesn't initialize it at all, so foo._bar can hold any value (including 0).
Foo()
This value-initializes the temporary object, which in case of trivial default constructor means zero-initialization, so Foo()._bar is equal to 0.
n3376 quotes
8.5/11
If no initializer is specified for an object, the object is
default-initialized; if no initialization is performed, an object with
automatic or dynamic storage duration has indeterminate value. [ Note:
Objects with static or thread storage duration are zero-initialized,
see 3.6.2. — end note ]
8.5/6
To default-initialize an object of type T means: if T is a (possibly
cv-qualified) class type (Clause 9), the default constructor for T is
called (and the initialization is ill-formed if T has no accessible
default constructor);
8.5/10
An object whose initializer is an empty set of parentheses, i.e., (),
shall be value-initialized.
8.5/7
To value-initialize an object of type T means:
...
otherwise, the object is zero-initialized.
8.5/5
To zero-initialize an object or reference of type T means: if T is a
(possibly cv-qualified) non-union class type, each non-static data
member and each base-class subobject is zero-initialized and padding
is initialized to zero bits;
So, in your case, there are nor static storage duration variables, nor thread-local variables, so objects foo and b will be default-initialized, that means, that constructor will be called. Default-constructor (not user-defined) will not initialize members and in members will be arbitrary garbage and this arbitrary garbage may be 0 (thanks to Jarod42 for point this in comment).
And Foo().printBar(); should print 0, since object is zero-initialized.
I would like to make a type that wraps a numeric type (and provides additional functionality).
Furthermore, I need the number and the wrapper to be both implicitly convertible to each other.
So far I have:
template<class T>
struct Wrapper
{
T value;
Wrapper() { }
Wrapper(T const &value) : value(value) { }
// ... operators defined here ...
};
It's almost good, but it doesn't quite behave the same as a built-in type:
#include <iostream>
int main()
{
unsigned int x1, x2 = unsigned int();
Wrapper<unsigned int> y1, y2 = Wrapper<unsigned int>();
std::cerr << x1 << std::endl; // uninitialized, as expected
std::cerr << y1.value << std::endl; // uninitialized, as expected
std::cerr << x2 << std::endl; // zero-initialized, as expected
std::cerr << y2.value << std::endl; // uninitialized!?!
}
Is there any way for me to design the Wrapper such that statements like
Wrapper<unsigned int> y2 = Wrapper<unsigned int>();
initialize the value inside, but without forcing statements like
Wrapper<unsigned int> y1;
to also do the same?
In other words, is it possible to make a type that behaves exactly the same as a built-in type in terms of initialization?
Updated Answer
Okay, so as dyp points out, I and everyone else was wrong. You can achieve what you want to do by = default with the default constructor:
Wrapper() = default ;
^^^^^^^^^
This works because without an initializer you obtain the same behavior I outline before but when you use value initialization the behavior changes as outlined in paragraph 8:
— if T is a (possibly cv-qualified) non-union class type without a user-provided or deleted default constructor, then the object is zero-initialized and, if T has a non-trivial default constructor, default-initialized;
Original Answer
I don't think there is a way to make this work the way you would like. Class types act differently that builtin types we can see this from the draft standard section 8.5 Initializers paragraph 12 which says (emphasis mine going forward):
If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value. [ Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. —end note ]
and we can see this has different results for classes than built-in types from paragraph 7 which says:
To default-initialize an object of type T means:
and includes the following bullets:
— if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, no initialization is performed.
and if we look at paragraph 11 for the second case Wrapper<unsigned int>() it says:
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
and then back to paragraph 8:
To value-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized; [...]
So we end up with the same behavior.
Both Praetorian and aschepler gave you options that work slightly differently but appear to achieve the behavior you would like just not with the same syntax.
I don't think there's any way to achieve what you're looking for. As soon as you define a default constructor for a class that will be called whether you provide or omit parentheses when defining an instance of the class.
You can get kinda close by declaring the following constructor; the variable definition will require an empty pair of braces to achieve value initialization.
Wrapper(std::initializer_list<std::initializer_list<T>> /*unused*/) : value() {}
auto y3 = Wrapper<unsigned int>({}); // y3.value will be value initialized
Live demo
But I'd sooner drop the requirement for implicit conversion to Wrapper, and keep the class an aggregate, than implement the solution above.
Unfortunately, not that I can think of. C++ implicitly converts class_type name to call the default constructor. You would have to make the default constructor do what you'd expect an un-initialized primitive type to do.
If you remove the user-provided constructor, you can leave the member uninitialized when default-constructing, or value-initialize the wrapper and in doing so zero-initialize its storage (and therefore its member):
unsigned int x1, x2 {}; // One uninitialized, one value-initialized
Wrapper<unsigned int> y1, y2 {}; // Ditto
You can still set the value during construction via aggregate-initialization:
Wrapper<int> z {42};
At any rate, this is largely unnecessary; uninitialized values are rarely useful except to introduce subtle, difficult-to-reproduce bugs. I would recommend value-initializing the member either in the default constructor or in the member declaration.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
What do the following phrases mean in C++: zero-, default- and value-initialization?
Today I came to know about 3 types of initialization in C++:
Zero Initialization
Default Initialization
Value Initialization
I have googled about it but I found no satisfactory results. All I get is a few standards. What I have understood until now is this: in case of value initialization, a data member can get value equal to zero in some cases.
Please elaborate them (standards) with examples. Also please don't just provide the text from the standard.
Thanks
The types of initialization refer to the language grammar. Here are two examples:
T * p1 = new T;
T * p2 = new T();
The object *p1 is default-initialized, and the object *p2 is value-initialized.
The effect of the initialization depends on the type T: 1) If T is a fundamental, then default-initialization does nothing (i.e. the object is left uninitialized), while value initialization equals zero initialization in that case and means the object is set to zero.
2) If T is an aggregate (i.e. class without constructors or destructor or assignment operator), then each element is recursively default- or value-initialized.
3) If T is of class-type and does have user-defined constructors, then both default- and value-initialization cause a call to the default constructor.
Note that member objects of classes with constructors can in turn be default- or value-initialized:
struct Foo {
int x;
int y;
Foo() : x() { }
};
Now when you say Foo a; then a is default-initialized, so the default constructor is called. This in turn causes a.x to be value-, i.e. zero-initialized, while a.y remains default-, i.e. un-initialized.
(Note that it's not really possible to value-initialize an automatic object, though in C++11, brace-initialization may be used to cause value-initialization, as in Foo a{};. (This behaves exactly the same as Foo a; in our example, consequent to the third paragraph.))
This is dealt with in 8.5 Initializers [dcl.init].
Zero Initialization
5/ To zero-initialize an object or reference of type T means:
— if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression, converted to T. As specified in 4.10, converting an integral constant expression whose value is 0 to a pointer type results in a null pointer
value.
— if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized and padding is initialized to zero bits;
— if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zeroinitialized and padding is initialized to zero bits;
— if T is an array type, each element is zero-initialized;
— if T is a reference type, no initialization is performed.
Basically, it's equivalent to a memset(&obj, 0, sizeof(objt));, except that it account that the memory representation of a null pointer might not be a 0 value (even though it is represented by a 0 in the language).
// foo.cpp
static char const* p; // p is zero-initialized
// during static initialization
static void init() {
if (!p) { p = new char[500]; } // fine as p has been 0-initialized
}
Note: personally I still prefer to use = nullptr to initialize p, just to make the intent clear...
Default Initialization
6/ To default-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, no initialization is performed.
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
Or basically, a call to the default constructor, accounting for arrays, at least for classes. The last point is a caveat for built-ins (such as int). Those are simply left as is (with garbage inside).
Default initialization is what is called when you defined a variable but do not initialize it explicitly. It is also what happens to attributes of a class that are not listed in the initializer list. So the caveat for built-ins is quite important to a programmer.
int function() {
int a; // <-- a is default-initialized (which means nothing happens...)
return a; // <-- uses a, so technically undefined behavior
}
struct A { int a; A() {} }; // During the call to A::A(),
// A::a is default-initialized (nothing happens...)
The absence of explicit initialization is a left-over from C. It's normally so for optimization reasons but leads to Undefined Behavior if one attempts to use the value...
Value Initialization
7/ To value-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized.
An object that is value-initialized is deemed to be constructed and thus subject to provisions of this International Standard applying to “constructed” objects, objects “for which the constructor has completed,” etc., even if no constructor is invoked for the object’s initialization.
It is a mix of both the above, meaning that the following syntax:
template <typename T> T value() { return T(); }
^~~
provides a suitably initialized instance of T whether T is a class type or a built-in type. It's important for templated code to be able to have such a unified syntax.
Note that with C++11, it is also possible to use T{} to achieve the same effect (which helps disambiguates from functions).