Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: initialization of int variables by an implicit constructor

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.

like image 406
usual me Avatar asked Dec 15 '22 08:12

usual me


2 Answers

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.

like image 54
Pixelchemist Avatar answered May 15 '23 03:05

Pixelchemist


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.

like image 40
AnT Avatar answered May 15 '23 01:05

AnT