This question already has answers here:
Value initialization and Non POD types
(2 answers)
Closed 8 years ago.
Using Microsoft Visual Studio Ultimate 2013 update 4 and the following code:
#include <iostream>
auto main() -> int {
struct Base { int a; };
struct Derived : Base { int b; };
auto foo = Derived();
std::cout << foo.a << " " << foo.b;
}
I get this output:
-858993460 -858993460
But I expected:
0 0
Why is foo not zero-initialized?
Should be initialized to zero, looks like MSVC bug.
Since actually your code is like this
Derived foo{Derived()};
then copy/move constructor will be called on temporary object initialized with ().
n3376 8.5/10
An object whose initializer is an empty set of parentheses, i.e., (),
shall be value-initialized.
n3376 8.5/7
To value-initialize an object of type T means:
if T is a (possibly cv-qualified) non-union class type without a
user-provided or deleted default construc- tor, then the object is
zero-initialized and, if T has a non-trivial default constructor,
default-initialized;
n3376 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;
Your structs have no constructors, so default one are created.
Default constructor of a struct will call default constructor for each of memebers.
Default constructor of int doesn't initialize it. So int memeber will contain random data.
Add constructors to your structs and initialize memebers. Like this:
struct Base
{
Base(): a(0) {}
int a;
};
Related
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 know that default initialization for non-POD types will also default initialize non-static non-POD member variables by calling their default constructor. But I'm not sure exactly how this happens. Here is an example of what I mean:
#include <iostream>
#include <vector>
using namespace std;
class Test2 {
public:
Test2() {cout <<"Here";}
};
class Test {
public:
Test() {}
Test2 i;
};
int main() {
Test foo;
}
The output is:
Here
Based on the C++ standard on initializers (8.5), for default initialization:
— 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);
So given this, I do expect that the default constructor Test() will get called, but my empty default constructor for the class Test does not initialize Test2 i explicitly yet clearly, Test2() is getting called implicitly somehow. What I'm wondering is how this happens?
Similarly, for value initialization (not related to example above), if an empty user defined default constructor does not explicitly zero initialize a POD non-static member variable, how does that variable get zero initialized (which I know it does do)? Since based on the standard, it seems that for value initialization, all that happens when you have a user defined default constructor is that the constructor gets called.
The corresponding part of the C++ standard for value initialization is the following:
— if T is a class type (clause 9) with a user-declared constructor (12.1), then the
default constructor for T is called (and the initialization is ill-formed if T has no
accessible default constructor);
This question is similar to c++ empty constructor and member initialization
But the difference is that instead of asking what the end result behavior is, I'd like to know why the end result behavior happens.
In the C++11 standard, section 12.6 paragraph 8:
In a non-delegating constructor, if a given non-static data member or base class is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then
if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized
as specified in 8.5;
otherwise, if the entity is a variant member (9.5), no initialization is performed;
otherwise, the entity is default-initialized (8.5).
You are encountering the third case, where there is no initializer for the member and the member isn't a variant member, so in that case it is default-initialized.
Also, from paragraph 10:
In a non-delegating constructor, initialization proceeds in the following order:
- First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list
(regardless of the order of the mem-initializers).
Then, non-static data members are initialized in the order they were declared in the class definition
(again regardless of the order of the mem-initializers).
Finally, the compound-statement of the constructor body is executed.
Regardless of what you specify in your constructor, the members are going to be initialized just before the body of the constructor is executed.
A mem-initializer-id is the identifier used to refer to a member in a constructor initializer list:
class Test {
public:
Test() : i() {} // Here `i` is a mem-initializer-id
Test2 i;
};
Value initialization of a type with a user-defined default constructor performs no initialization on non-static POD members if they are not explicitly initialized in the constructor. E.g., in this program:
#include <iostream>
using namespace std;
struct Foo {
// Foo has a user-defined default constructor
// that does not initialize i
Foo() {}
int i;
};
int main() {
Foo x{}; // value-initialize x
cout << x.i << endl;
}
x.i is uninitialized. The program therefore technically has undefined behavior, but in this case "undefined behavior" most likely means that it will print an unspecified integer value that is likely not 0.
Language lawyer argument:
§12.6.1p2: "An object of class type can also be initialized by a braced-init-list. List-initialization semantics apply; see 8.5 and 8.5.4."
§8.5.4p3: "List-initialization of an object or reference of type T is defined as follows: ... If the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized."
§8.5p7: "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)
According to the draft of the C++ standard found at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf, section 12.6.2:
If a given non-static data member or base class is not named by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer), then
— If the entity is a non-static data member of (possibly cv-qualified) class type (or array thereof) or a base class, and the entity class is a non-POD class, the entity is default-initialized (8.5). If the entity is a non-static data member of a const-qualified type, the entity class shall have a user-declared default constructor.
— Otherwise, the entity is not initialized. If the entity is of const-qualified type or reference type, or of a (possibly cv-qualified) POD class type (or array thereof) containing (directly or indirectly) a member of a const-qualified type, the program is ill-formed.
In other words, if an object of a non-POD class type does not appear in an initializer list, the compiler interprets this as if the object had appeared with its default constructor being called.
Also, note that other types (i.e. primitives and POD types) are not initialized, which is different from what you indicated in your question. Global objects are zero-initialized, but the same isn't true for objects on the stack. Here is a small program I put together to test this:
#include <iostream>
class T
{
public:
T() {}
void put(std::ostream &out)
{
out << "a = " << a << std::endl;
out << "b = " << b << std::endl;
out << "c = " << c << std::endl;
}
private:
int a;
int b;
int c;
};
T t2;
int main()
{
T t;
t.put(std::cout);
t2.put(std::cout);
return 0;
}
Compiling with g++ 4.5.2, I got the following output:
a = 8601256
b = 3
c = 2130567168
a = 0
b = 0
c = 0
Bjarne wrote:-
For a type T, T() is the notation for the default value , as defined by the default constructor .
What happen when we don't declare default constructor ? For example
using namespace std;
class date{
int n,m;
public:
int day(){return n;}
int month(){return m;}
};//no default constructor
int main()
{
date any =date();
cout<<any.month()<<endl;
cout<<any.day()<<endl;
return 0;
}
Output of this program is 0 and 0 every time i run my program. I haven't declare any default constructor then why there exits a default value i.e. 0?
EDIT-
class date{
int n,m;
public:
date (){
m=1;}
int day(){return n;}
int month(){return m;}
};
int main()
{
date any =date();
cout<<any.month()<<endl;
cout<<any.day()<<endl;
return 0;
}
After reading answers i provide a default constructor but now n is getting garbage value but according to answers it should be 0 as m is out of reach of any other constructor and it is value initialisation as mentioned in answer
The behavior you see is Well-Defined for your class.
How & Why is the behavior Well-Defined?
The rule is:
If you do not provide a no argument constructor the compiler generates one for your program in case your program needs one.
Caveat:
The compiler does not generate the no argument constructor if your program defines any constructor for the class.
As per the C++ Standard an object can be initialized in 3 ways:
Zero Initialization
Default Initialization &
Value Initialization
When, a type name or constructor initializer is followed by () the initialization is through value initialization.
Thus,
date any =date();
^^^
Value Initializes an nameless object and then copies it in to the local object any,
while:
date any;
would be a Default Initialization.
Value Initialization gives an initial value of zero to members that are out of reach of any constructor.
In your program, n and m are beyond the reach of any constructor and hence get initialized to 0.
Answer to Edited Question:
In your edited case, your class provides a no argument constructor, date(), which is capable(& should) initialize members n and m, but this constructor doesn't initialize both the members, So In this case no zero initialization takes place, and the uninitialized members in the object have an Indeterminate(any random) value, further this temporary object is copied to any object which displays the shows indeterminate member values.
For Standerdese Fans:
The rules for object Initialization are aptly defined in:
C++03 Standard 8.5/5:
To zero-initialize an object of type T means:
— if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
— if T is a non-union class type, each nonstatic data member and each base-class subobject is zero-initialized;
— if T is a union type, the object’s first named data member is zero-initialized;
— if T is an array type, each element is zero-initialized;
— if T is a reference type, no initialization is performed.
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.
To value-initialize an object of type T means:
— if T is a class type (clause 9) with a user-declared 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 non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized
Because compiler, cursing under its breath, generates one for you.
EDIT: Since Als said it does not answer question, I'll elaborate. When you use date any = date();, you call compiler-generated default constructor. This constructor calls default constructors for all base classes and data members. For your data members int default constructor is int(), which sets value to 0. Here is code on ideone.com
#include <iostream>
int main( void )
{
int i = -123;
i = int();
std::cout << i << std::endl;
return( 0 );
}
Program output:
0
From the C++ draft standard (December 1996 Working Paper):
If there is no user-declared constructor for class X, a default constructor is implicitly declared. An implicitly-declared default constructor is an inline public member of its class.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
uninitialized const
I understand that a const object needs to initialized.
So for the following code,
class sample
{};
int main()
{
const sample obj;
return 0;
}
the compiler will complain because the const object obj is not initialized.
But when i modify the code(show below) with a default constructor, the compiler will not throw any error.
class sample
{
public:
sample() { }
};
int main()
{
const sample obj;
return 0;
}
What is the thing that the newly added default ctor does which satisfies the compiler?
What is the thing that the newly added default ctor does which satisfies the compiler?
Because that is the requirement imposed by the C++ standard when declaring objects with the const qualifer.
Reference:
C++03 8.5 Initializers 8 Declarators
§9:
If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor. Otherwise, if no initializer is specified for a nonstatic object, the object and its subobjects, if any, have an indeterminate initial value90); if the object or any of its subobjects are of const-qualified type, the program is ill-formed.
You're doing a default initialization of a const-qualified type. The C++ (C++11 draft n3290) standard has this to say about that (§8.5/6 Initializers):
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.
Your first sample doesn't conform to this (no user-provided constructor). The second does.
class A {
public:
A();
private:
char a[5];
int* ptr;
};
A::A() : a(0), ptr(0) { }
Is this right?
The only sensible thing you can do with a C-array in C++03 is value-initialize it (in C++11 and beyond it can be list-initialized).
From the C++03 standard, §8.5/7:
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
And from §8.5/5:
To value-initialize an object of type T means:
if T is a class type with a user-declared constructor, 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 non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
if T is an array type, then each element is value-initialized;
otherwise, the object is zero-initialized
To zero-initialize an object of type T means:
if T is a scalar type, the object is set to the value of 0 (zero) converted to T;
if T is a non-union class type, each nonstatic data member and each base-class subobject is zero-initialized;
if T is a union type, the object’s first named data member) is zero-initialized;
if T is an array type, each element is zero-initialized;
if T is a reference type, no initialization is performed.
So, if your constructor definition is changed to
A::A() : a(), ptr() { }
then you are guaranteed that post-construction, all 5 elements of A::a will have the value '\0' and A::ptr will be null.
Afraid not; C++ doesn't support initialising arrays like this.
You'll just have to assign to its members in A's constructor body, or you can use value-initialisation if you don't really care what the values are:
struct A {
int x[5];
A() : x();
};
C++0x does let you give all the values, though:
struct A {
int x[5];
A() : x{1,2,3,4,5} {}
};
Note, though, that because arrays are not class-objects, you won't be able to do this:
struct A {
int x[5];
A(std::initializer_list<int[5]>& i) // or whatever the T should be
: x{i} // or x(i)
{}
}
A a({1,2,3,4,5)};