Consider the following code:
#include <iostream>
template<class T>
void f(T& t)
{
t = T();
}
int main()
{
int x = 42;
f(x);
std::cout << x;
}
Does the C++11 standard define what the output shall be? My compiler outputs 0, however I was under the impression the default constructor of a primitive type is a null operation or undefined behaviour.
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 forT == intevaluated 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
is guaranteed to initialize
swith zeros (boths.xands.y) despite that fact that classShas a default constructor. I brought up this example specifically to illustrate the fact that even in situations when the default constructor exists, theT()expression can still completely ignore it and work by its own rules instead.