为什么 std::array<int, 10> x 没有被零初始化,但是 std::array<int, 10> x = std::array<int, 10>() 似乎是呢?

16
我刚刚提出了两个关于数组和值初始化的问题这里这里。 但是对于这段代码,我感到迷茫:
#include <iostream>
#include <iomanip>
#include <array>

template <class T, class U = decltype(std::declval<T>().at(0))>
inline U f1(const unsigned int i)
{T x; return x.at(i);}

template <class T, class U = decltype(std::declval<T>().at(0))>
inline U f2(const unsigned int i)
{T x = T(); return x.at(i);}

int main()
{
    static const unsigned int n = 10;
    static const unsigned int w = 20;
    for (unsigned int i = 0; i < n; ++i) {
        std::cout<<std::setw(w)<<i;
        std::cout<<std::setw(w)<<f1<std::array<int, n>>(i);
        std::cout<<std::setw(w)<<f2<std::array<int, n>>(i);
        std::cout<<std::setw(w)<<std::endl;
    }
    return 0;
}

正如预期的那样,f1返回任意值,因为它的值没有进行零初始化。但是f2似乎只返回零值:

                   0                   0                   0
                   1                  61                   0
                   2                   0                   0
                   3                   0                   0
                   4           297887440                   0
                   5               32767                   0
                   6             4196848                   0
                   7                   0                   0
                   8           297887664                   0
                   9               32767                   0

个人认为f2将创建一个具有任意值的数组并将其复制/移动到x。但事实似乎并非如此。

所以,我有两个问题:

  • 为什么?
  • 在这种情况下,C++11的std::array<T,N>和C风格的T[N]是否具有相同的行为?

3
T() 是一个经过值初始化的 T。如果 T 是 C 风格的数组类型,则会出现无效的语法。更普遍适用的语法是 T x = {};T x{}; - Casey
@Casey 值初始化适用于 C 风格数组。如果 T 不是简单类型说明符,即单个标识符或命名类型的关键字,则 T() 是语法错误。在 C++03 中,= {} 仅适用于数组,而简单的 {} 则是错误的。 - Potatoswatter
@Potatoswatter 我并没有暗示值初始化不适用于C风格的数组。简单类型说明符也可以是类型名称(包括typedef名称)或简单模板ID。问题是关于C++11的。 - Casey
请注意,5.2.3/2 定义了函数式转换符号:“表达式 T(),其中 T 是非数组完整对象类型的 简单类型说明符类型名说明符,或者是(可能带有 cv 限定符的)void 类型,创建指定类型的 prvalue,该 prvalue 是值初始化的(8.5;对于 void() 情况不执行任何初始化)。" 它明确禁止数组类型。 - Casey
@Potatoswatter 这个问题是“为什么语法A会将这个数组清零,而语法B则不会?”我认为我的关于语法的陈述已经足以区分这两者了,因为在之前Vincent的两个问题的答案中已经有了非常全面的关于默认初始化和值初始化的讨论。(1) (2)。 - Casey
显示剩余4条评论
1个回答

19
使用 {}() 作为初始化器,带或不带 =,都会导致值初始化。对于具有隐式声明构造函数的类型,值初始化实现了零初始化,它将每个原始元素设置为 0,正如其名称所示。这发生在构造函数运行之前,但在这种情况下,构造函数什么也不做。
因为构造函数什么也不做(它是平凡的),所以可能看到未初始化的数据。
至于 C 风格的数组,如果您使用 = {} 而不是 = T(),则行为类似,因为后者是非法的。 T() 将要求分配临时数组对象给命名对象,但是数组不能被分配。另一方面,= {} 将一个花括号初始化列表分配给数组,而花括号初始化列表是一种既不是表达式也不是对象的特殊语法结构。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接