Default constructor of primitive types in assignment to anonymous instance

There's no "default constructor" involved in your code. Only class types can have constructors. Scalar types have no constructors, default or otherwise.

The T() syntax creates a temporary object initialized by so called value-initialization. Value-initialization resolves to constructor call only for class types, and only for those with user-defined constructors (with some nuances in C++11). For other types value-initialization does not involve any constructors at all. It proceeds in accordance with its own specific and rather elaborate initialization rules that define the initial value of the data directly, without involving any constructors (see 8.5 in the language specification).

For scalar types value-initialization performs zero-initialization. This is why your code is guaranteed to output zero. The exact specifics of the abstract initialization process changed between the versions of C++ language standard, however since the beginning of times C++ language guaranteed that T() expression for T == int evaluated to zero. I.e. even in C++98 your code will output zero.

It is a common misconception that all these T(...) expressions somehow necessarily imply constructor calls. In reality, T(...) expression is a functional cast expression (regardless of the number of arguments) (see 5.2.3 in the language specification), which might resolve to constructor call in some narrow set of specific situations and has nothing to do with any constructors in other situations.

For example, this code

struct S { int x, y; };

S s = S();

is guaranteed to initialize s with zeros (both s.x and s.y) despite that fact that class S has a default constructor. I brought up this example specifically to illustrate the fact that even in situations when the default constructor exists, the T() expression can still completely ignore it and work by its own rules instead.


Here is what the standard says regarding your question:

In 8.5. paragraph 10:

An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.


In 8.5. paragraph 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.

emphasis mine. So, since int isn't even a class type, it falls under the last rule, and gets zero-initialized, so it's an absolutely correct behavior.

Tags:

C++

C++11