【问题标题】:How variable is initialized by default constructor in c++c++中的默认构造函数如何初始化变量
【发布时间】:2013-12-11 07:29:07
【问题描述】:

给定以下教程中的函数模板。

template<class T>
double GetAverage(T tArray[], int nElements)
{
    T tSum = T(); // tSum = 0

    for (int nIndex = 0; nIndex < nElements; ++nIndex)
    {
        tSum += tArray[nIndex];
    }

    // Whatever type of T is, convert to double
    return double(tSum) / nElements;
}

排队

T tSum = T(); // tSum = 0

他们说它将调用特定类型的默认构造函数(基于我们调用此函数的类型)。我怀疑这个调​​用如何将值分配给 tSum,因为这会很好地调用构造函数。但是由于构造函数没有返回任何内容,因此 iSum 如何初始化为 int 的 0 或 double 的 0.0。

【问题讨论】:

标签: c++ templates


【解决方案1】:

您正在阅读的教程对术语进行了严重的扭曲/简化。声明说

T tSum = T();

调用“默认构造函数”不正确。显而易见的是,在一般情况下,T 类型很容易成为非类类型。非类类型没有任何构造函数,但上面的初始化对它们也是有效的。

在这种情况下,正确的术语是值初始化。表达式T() 生成一个由值初始化 进程初始化的T 类型的临时对象。值初始化按照它自己的特定规则工作,它根本不需要任何构造函数。对于非类类型以及某些类别的类类型,它以完全无构造函数的方式进行。

例如,表达式int() 产生0 类型的值int - 这就是值初始化对int 类型(以及所有标量类型)的意义。当然,它不涉及任何“默认构造函数”,因为类型 int 不可能有任何构造函数。

同样,表达式 T() 不是构造函数调用,因为该教程似乎错误地说明了这一点。表达式T() 实际上是一个没有操作数的函数式转换。如上所述,没有操作数的函数式强制转换会产生一个 T 类型的值初始化临时对象。它不依赖于构造函数“返回”任何东西。

如果T() 表达式的临时值随后用作tSum 对象的初始化器。此语法从T() 调用tSum 的复制初始化。

【讨论】:

    【解决方案2】:

    声明

    T tSum = T();
    

    表示“使用默认构造函数构造 T 类型的临时构造,然后复制/移动构造 tSum”,参见 C++ n3376 ch8.5,p14。允许编译器(并且可能会)将其优化为就地默认构造 T tSum;参见 C++ n3376 ch12.8,p31,复制省略,但复制/移动构造函数必须 可用,参见 C++ n3376 ch12.8 p32(考虑删除 T 的复制/移动构造函数,它将无法编译)。

    【讨论】:

      【解决方案3】:

      T() 实际上创建了一个T 类型的临时对象,调用默认构造函数对其进行初始化。然后你就有了临时对象本身。

      所以

      T tSum = T();
      

      将使用 T 的默认初始化临时实例初始化 tSum

      如果T 是一个带有构造函数的类,这一切似乎都是不必要的,但如果T 是一个基本类型(例如int),它会将tSum 初始化为0。由于在您编写模板时,T 的性质是未知的,因此代码可以安全使用。

      【讨论】:

      • 所以如果我没记错的话,它也会调用一个拷贝构造函数。
      • 或者在c++11中移动构造函数。
      • @Devesh Agrawal 实际上,它不会。它将优化复制/移动构造。您可以通过定义自己的打印输出的默认/复制构造函数来检查。
      • 另请注意,在 C++11 中,您可以使用 T tSum{}; 实现相同的目的
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      • 1970-01-01
      • 2020-01-18
      相关资源
      最近更新 更多