C ++ 11:分配给匿名实例的基本类型的默认构造函数

时间:2012-11-16 07:50:44

标签: c++ c++11

请考虑以下代码:

#include <iostream>

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

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

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

2 个答案:

答案 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(); (即ss.x都将为零),尽管类s.y具有默认构造函数,但不执行此操作任何东西。我特意提出这个例子来说明这样一个事实,即使在默认构造函数存在的情况下,S表达式仍然可以完全忽略它,而是按照自己的规则工作。

答案 1 :(得分:4)

以下是关于您的问题的标准:

8.5中。第10段:

一个对象,其初始化程序是一组空的括号,即(),应进行值初始化。


8.5中。第7段:

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

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

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