C++ Default constructor - c++

Given the following code:
class temp
{
public:
string str;
int num;
};
int main()
{
temp temp1;
temp temp2 = temp();
cout << temp1.str << endl; //Print ""
cout << temp2.str << endl; //Print ""
cout << temp1.num << endl; //Print a rand num
cout << temp2.num << endl; //Print 0
}
What is the different between these two?—
temp temp1;
and
temp temp2 = temp();

temp temp1;
This calls temp's default constructor on the instance called temp1.
temp temp2 = temp();
This calls temp's default constructor on a temporary object, then calls the compiler-generated copy-constructor on temp2 with the temporary object as the argument (this of course assumes that the compiler doesn't elide copies; it depends on your compiler's optimization settings).
As for why you get different initialized values, section 8.5 of the standard is relevant:
8.5 Initializers [dcl.init]
Paragraph 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.
Paragraph 7: An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
Paragraph 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 value; if the object or any of its subobjects are of const-qualified type, the program is ill-formed.
12 Special Member Functions [special]
Paragraph 7: An implicitly-declared default constructor for a class is implicitly defined when it is used to create an object of its class type (1.8). The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with an empty mem-initializer-list (12.6.2) and an empty function body.
12.6.2 Initializing bases and members [class.base.init]
Paragraph 4: If a given nonstatic 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 nonstatic 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 nonstatic 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.
So now that the rules have been laid out, let's see how they apply:
temp temp1;
temp is a non-POD type (because it has a std::string member), and since no initializer is specified for temp1, it will be default-initialized (8.5/9). This calls the default constructor (8.5/5). temp has an implicit default constructor (12/7) which default-initializes the std::string member and the int member isn't initialized at all (12.6.2/4).
temp temp2 = temp();
On the other hand, the temporary temp object is value-initialized (8.5/7), which value-initializes all data members (8.5/5), which calls the default constructor in the std::string member and zero-initializes the int member (8.5/5).
Of course, if you much rather not have to refer to the standard in 5+ different places, just ensure that you explicitly initialize everything (e.g. int i = 0; or using initializer lists).

The behavior of your code depends critically on the compiler you are using. More precisely, it depends on which version of language specification your compiler implements.
For C++98 compilers, both declarations have identical effect on the final values of the objects being declared: the str member should become empty, while the num members should contain unpredictable value. In both cases the actual initialization is default-initialization performed by a compiler-provided default constructor of class temp. That default constructor initializes str, but leaves num uninitialized.
For C++03 compilers the behavior is different. There's no difference for temp1 object (its num is still unpredictable). But temp2 initialization is handled differently. In C++03 the () initializer triggers the new kind of initialization - so called value-initialization. Value-initialization ignores the compiler-provided default constructor of the top level object, and instead works directly on its subobjects (data members in this case). So the temp2 object is effectively initialized by value-initialization, which also sets the num member to zero (in addition to initializing str with an empty string). For this reason, temp2.num ends up being zero in C++03 compilers.
If in your experiments you observed consistent zero in temp2.num, it means that your compiler follows the C++03 specification in this respect.

temp temp1;
Will create a default initialized temp object. Since you provided no default constructor for temp, every member of temp will be default initialized too. Since std::string provides a default ctor, it gets initialized correctly and has a well-defined value. The integer, however, gets default initialized, which is implementation defined and normally a random value.
temp temp2 = temp();
This will first create a value initialized temp object. This is important, because the object itself is value initialized, so are its members. It doesn't matter for the string, as default and value initialization are the same, but it matters for the integer. A value initialized integer has the value 0.
After that, you just copy over those members into temp2.
Also, this relevant question might be of interest to you.
Edit: See my comment on #In silico's answer for explanation on why this isn't the case for MSVC. :/

Related

Does a constructor / destructor have to have code, or is the function enough?

So if I have a class
class Transaction {
int no;
char dollar;
public:
Transaction();
~Transaction();
}
And in my constructor / destructor
Transaction::Transaction {
cout << "Entering constructor" << endl;
}
Transaction::~Transaction {
cout << "Leaving program" << endl;
}
is that code enough for my constructor and destructor to work? Will it set the data members in my class to a safe state even though I declare nothing in my constructor?
Each subobject will be default initialized, if you provide a constructor without specifying initializers for said subobject.
Section 8.5 of the Standard provides that:
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 that
To default-initialize an object of type T means:
if T is a (possibly cv-qualified) class type, 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.
There are two ways to initialize subobjects: in the ctor-initializer-list, and in a brace-or-equal-initializer in the member declaration (for non-static members the latter is new in C++11).
In practice, this means that when you don't provide an initializer, variables of primitive type, such as int and char, retain whatever value was left in memory previously. In most cases it's extremely hard to predict what value that will be, but you should be aware that it could be a leftover sensitive datum such as a password.
In the case of initialization of variables of static storage duration (such as objects at namespace scope and their members), the Standard further provides (same section) that:
Every object of static storage duration is zero-initialized at program startup before any other initialization takes place.
This is subtly different from what happens during value-initialization if you did not define a constructor:
To value-initialize an object of type T means:
if T is a (possibly cv-qualified) class type with a user-provided 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 (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.
but the effect is the same -- primitive members are set to zero and all others have their zero-argument constructor invoked.
nneonneo's advice to initialize all members explicitly is good, since having zero-initialization only for variables of static storage duration often leads to difficult-to-find bugs. But it's perfectly viable to use the brace-or-equal-initializer technique:
class Transaction
{
int no = 0;
char dollar = 0;
public:
Transaction();
~Transaction();
}
Your class has only simple data members, so you don't even need (or should want) a destructor.
You should, however, initialize your data members in the constructor:
Transaction::Transaction()
: no(0), dollar('$') {
cout << "Entering constructor" << endl;
}
Otherwise, they will not be initialized, and may contain random values (C++ doesn't guarantee initialization of primitive non-static members to any particular value if you don't initialize them in the constructor). This can be particularly insidious if you have pointer members.
No, it does not have to have code. In fact, in most languages you can leave it out and it will construct the class properly.

Default value of a function pointer in C++

What is the default value of a function pointer in C++? (Apparently it can't be NULL, so what is it?)
How is this program supposed to behave and why?
struct S { void (*f)(); };
int main()
{
S s = S();
s.f(); // What is the value of s.f?
}
First any pointer can be null. It is the one universal truth about pointers. That said, yours will be null, but not necessarily for the reasons you may think;
C++11 § 8.5,p10
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
This is important because your declaration includes this :
S s = S();
By the definition of value initialization:
C++11 § 8.5,p7
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.
Which brings us to what it means for your object-type to be zero-initialized:
C++11 § 8.5,p5
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 (103)
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 zero- initialized 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.
103) As specified in 4.10, converting an integral constant expression whose value is 0 to a pointer type results in a null pointer value.
The latter is the reason you're pointer is null. It will not be guaranteed-so by the standard given the same code, but changing the declaration of s to this:
S s;
Given a declaration like the above, a different path is taken through the standard:
C++11 § 8.5,p11
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.
Which then begs the last question, what is default initialization:
C++11 § 8.5,p6
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.
In your case the object s is zero-initialized which means the function pointer is NULL.
struct S { void (*f)(); };
int main()
{
S s = S();
if ( s.f == NULL)
std::cout << "s.f is NULL" << std::endl;
}
Output:
s.f is NULL
Online demo.
A function pointer can be NULL and you may assign NULL to it. Have a look here for instance:
#include <iostream>
using namespace std;
struct S { void (*f)(); };
int main()
{
S s = S();
s.f = NULL;
return 0;
}
I believe the way you call the constructor of the structure(with ()), f will be NULL.
Function pointer can be NULL, this way you can indicate that they don't point to anything!
In C++ (and C), pointers (regardless of type) do not have a default value per se; they take what ever happens to be in memory at the time. However, they do have a default initialised value of NULL.
Default Initialisation
When you don't explicitly define a constructor, C++ will call the default initialiser on each member variable, which will initialise pointers to 0. However, if you define a constructor, but do not set the value for a pointer, it does not have a default value. The behaviour is the same for integers, floats and doubles.
Aside
int main()
{
S s = S();
s.f(); // <-- This is calling `f`, not getting the pointer value.
}

Default values in C++ initializer lists

I only just learned yesterday that specifying parameters to initializer list items is optional. However, what are the rules for what happens in this case?
In the below example, will ptr be initialized to 0, toggle to false, and Bar default-constructed? I guess this question is sort of redundant, because there would be little point in initializer lists if unspecified argument values == undefined behavior.
Could I also be pointed to the section of the C++ standard that states the behavior in the case of initializer list items not being given arguments?
class Bar
{
Bar() { }
};
class SomeClass;
class AnotherClass
{
public:
SomeClass *ptr;
bool toggle;
Bar bar;
AnotherClass() : ptr(), toggle(), bar() { }
// as opposed to...
// AnotherClass() : ptr(NULL), toggle(false), bar(Bar()) { }
};
Yes, the members will be initialized to zero and a default-constructed object respectively.
The C++ 11 standard specifies this behavior in 12.6.2/7:
The expression-list or braced-init-list in a mem-initializer is used
to initialize the designated subobject (or, in the case of a
delegating constructor, the complete class object) according to the
initialization rules of 8.5 for direct-initialization.
In turn, 8.5/10 reads:
An object whose initializer is an empty set of parentheses, i.e., (),
shall be value-initialized.
Paragraph 8.5/7 defines value-initialized:
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.
And finally, 8.5/5 defines zero-initialized:
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;
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 zero-
initialized 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.
In the below example, will ptr be initialized to 0, toggle to false, and Bar default-constructed?
Yes. If a member initialiser appears in the initialiser list with empty parentheses, then that member is value initialised. This means that numerical types will be initialised to zero, pointers to null, and classes with default constructors using that constructor.
If you don't include the member in the initialiser list at all, then it will instead be default initialised; in that case. numerical and pointer types will be left uninitialised.
Could I also be pointed to the section of the C++ standard that states the behavior in the case of initializer list items not being given arguments?
C++11 12.6.2/7 specifies that the rules are the same as for direct initialisation.
C++11 8.5/16 specifies that if the initialiser is (), the object is value-initialised.
C++11 8.5/7 defines value initialisation.
Initialisations are covered in [dcl.init] (aka 8.5)
Point 10 says:
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
Value-initialisation is, put simply, default construction for classes and zero-initialisation for non-class types.

default values from not defined constructor

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.

Question about object initialization semantics

I've been wondering about the language in the C++03 specification surrounding object initialization, specifically section 8.5 paragraph 9 which states,
"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 value; if the object or any
of its subobjects are of const-qualified type, the program is ill-formed."
I want to pay particular attention to the clause, "Otherwise, if no initializer is specified for a nonstatic
object, the object and its subobjects, if any, have an indeterminate initial value". According to section 8.5 paragraph 5, the definition of a default-initialization falls into three cases:
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.
So as I understand it, paragraph 9 is stating that if we have a non-POD class type that does not have an initializer, then it's default constructor would be called. What I'm confused by is what happens in the case of POD-class types ... it seems from the clause I highlighted that there is no mention of a default constructor call being required for POD-class types. Yet if I created a POD-class type like
struct POD_class
{
int a;
int b;
POD_class() { cout << "Default constructor called" << endl; }
};
int main()
{
POD_class test;
return 0;
}
the default constructor of POD_class seems to be called when this code is compiled and run with g++. Therefore, even if POD_class did not have a specific initializer, it seems it was still default-initialized, per case #1 in the definition of default-initialization, because a default constructor for the type was called.
Based on the above scenario, here is my question: For a POD-class, does not default initializing an object as paragraph 9 mentions for non-static POD-classes mean that its default constructor is not called, or that it's simply not zero-initialized?
Your POD_class is in fact not a POD class. A POD class cannot have a user-declared constructor.