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 difference between default-initialization —
temp temp1;
and copy-initialization with value-initialization
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:
T
means:
T
is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T
;T
is a non-union class type, each nonstatic data member and each base-class subobject is zero-initialized;T
is a union type, the object’s first named data member is zero-initialized;T
is an array type, each element is zero-initialized;T
is a reference type, no initialization is performed.To default-initialize an object of type T
means:
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);T
is an array type, each element is default-initialized;To value-initialize an object of type T
means:
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);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;T
is an array type, then each element is value-initialized;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).