请考虑以下代码:
#include <iostream>
template<class T>
void f(T& t)
{
t = T();
}
int main()
{
int x = 42;
f(x);
std::cout << x;
}
C ++ 11标准是否定义了输出是什么?我的编译器输出0,但我的印象是原始类型的默认构造函数是空操作或未定义的行为。
答案 0 :(得分:17)
您的代码中没有“默认构造函数”。只有类类型可以有构造函数。标量类型没有构造函数,默认或其他。
T()
语法创建一个由所谓的 value-initialization 初始化的临时对象。值初始化仅解析为类类型的构造函数调用,并且仅针对具有用户定义的构造函数的构造函数调用(在C ++ 11中具有一些细微差别)。对于其他类型,值初始化根本不涉及任何构造函数。它根据自己特定的,相当精细的初始化规则进行,直接定义数据的初始值,不涉及任何构造函数(参见语言规范中的8.5)。
对于标量类型,值初始化执行零初始化。这就是为什么您的代码保证输出零的原因。抽象初始化过程的确切细节在C ++语言标准版本之间发生了变化,但是自从C ++语言开始以来,T()
的{{1}}表达式被评估为零。即即使在C ++ 98中,您的代码也会输出零。
一种常见的误解是,所有这些T == int
表达式在某种程度上都必然意味着构造函数调用。实际上,T(...)
表达式是一个功能强制转换表达式(不论参数的数量)(参见语言规范中的5.2.3),它可能会在一些狭窄的特定情况下解析为构造函数调用,并且没有任何内容。在其他情况下使用任何构造函数。
例如,此代码
T(...)
保证用零初始化struct S { int x, y; };
S s = S();
(即s
和s.x
都将为零),尽管类s.y
具有默认构造函数,但不执行此操作任何东西。我特意提出这个例子来说明这样一个事实,即使在默认构造函数存在的情况下,S
表达式仍然可以完全忽略它,而是按照自己的规则工作。
答案 1 :(得分:4)
以下是关于您的问题的标准:
在 8.5中。第10段:
一个对象,其初始化程序是一组空的括号,即(),应进行值初始化。
在 8.5中。第7段:
对T类型的对象进行值初始化意味着:
int
甚至不是类类型,它属于最后一条规则,并且被初始化为零,因此它是绝对正确的行为。