9

考虑以下代码:

#include <iostream>

template<class T>
void f(T& t)
{
    t = T();
}

int main()
{
    int x = 42;
    f(x);
    std::cout << x;
}

C++11 标准是否定义了输出应该是什么?我的编译器输出 0,但是我的印象是原始类型的默认构造函数是空操作或未定义的行为。

4

2 回答 2

18

您的代码中不涉及“默认构造函数”。只有类类型可以有构造函数。标量类型没有默认或其他构造函数。

T()语法创建了一个由所谓的 value-initialization 初始化的临时对象。值初始化仅解析为类型的构造函数调用,并且仅适用于具有用户定义构造函数的那些(在 C++11 中有一些细微差别)。对于其他类型,值初始化根本不涉及任何构造函数。它按照自己特定且相当复杂的初始化规则进行,这些初始化规则直接定义数据的初始值,而不涉及任何构造函数(参见语言规范中的 8.5)。

对于标量类型,值初始化执行零初始化。这就是为什么您的代码保证输出为零的原因。抽象初始化过程的确切细节在 C++ 语言标准的版本之间发生了变化,但是从一开始 C++ 语言就保证该T()表达式的T == int计算结果为零。即,即使在 C++98 中,您的代码也会输出零。

一种常见的误解是,所有这些T(...)表达式都必然暗示构造函数调用。实际上,T(...)表达式是一个函数转换表达式(不管参数的数量)(参见语言规范中的 5.2.3),它可能会在某些特定情况下解析为构造函数调用,并且与任何构造函数无关其他情况。

例如,这段代码

struct S { int x, y; };

S s = S();

尽管类具有默认构造函数,但保证s用零(s.x和)初始化。我专门提出了这个例子来说明这样一个事实,即即使在存在默认构造函数的情况下,表达式仍然可以完全忽略它并按照自己的规则工作。s.yST()

于 2012-11-16T07:55:03.627 回答
4

以下是标准对您的问题的说明:

8.5 中。第10段:

初始值设定项为空括号集的对象,即 (),应进行值初始化。


8.5 中。第 7 段:

对 T 类型的对象进行值初始化意味着:

  • 如果 T 是具有用户提供的构造函数 (12.1) 的(可能是 cv 限定的)类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化格式错误) ;
  • 如果 T 是没有用户提供的构造函数的(可能是 cv 限定的)非联合类类型,则该对象是零初始化的,并且如果 T 的隐式声明的默认构造函数是非平凡的,则调用该构造函数。
  • 如果 T 是一个数组类型,那么每个元素都是值初始化的;
  • 否则,对象被零初始化。

强调我的。所以,由于int它甚至不是一个类类型,它属于最后一条规则,并且被零初始化,所以这是一个绝对正确的行为。

于 2012-11-16T08:00:44.170 回答