std::array的默认初始化是什么?

147
使用C++11的std::array,我是否保证语法std::array<T, N> x;将默认初始化数组的所有元素? 编辑:如果不是,请问是否有一种语法适用于所有数组(包括零大小的数组),以将所有元素初始化为它们的默认值? 编辑:在cppreference上,默认构造函数描述如下:
(constructor) (implicitly declared) (public member function)
default-constructs or copy-constructs every element of the array 

所以答案可能是肯定的。但我想根据标准或未来的标准确保这一点。


不是这样的。它是默认声明的,因此基本上相当于 T x[N] 语法。 - Rapptz
5个回答

213

根据定义,默认初始化是在没有指定其他初始化时发生的初始化;C++语言保证,对于您没有提供显式初始化程序的任何对象都将进行默认初始化(C++11 §8.5/11)。这包括类型为std :: array<T,N>T [N]的对象。

请注意,有些类型的默认初始化没有效果,并且会使对象的值不确定:任何非类、非数组类型(§8.5/6)。因此,具有这些类型的默认初始化对象数组将具有不确定的值,例如:

int plain_int;
int c_style_array[13];
std::array<int, 13> cxx_style_array;

无论是C风格的数组还是std::array,它们中的整数值都是不确定的,就像plain_int的值一样。

是否有一种语法可以初始化所有元素为它们的默认值(包括零大小的数组)?

我猜当你说“它们的默认值”时,实际上指的是“将所有元素初始化为T{}”。这不是默认初始化,而是值初始化(8.5/7)。您可以通过给每个声明一个空初始化器来方便地请求值初始化:

int plain_int{};
int c_style_array[13]{};
std::array<int, 13> cxx_style_array{};

这将按顺序对所有数组元素进行值初始化,导致plain_int和两种类型的数组的所有成员都被初始化为零。

4
根据标准,是的。注意在MSVC中可能会出现漏洞,它无法正确实现某些情况下的值初始化。 - Casey
1
确实,Boost库提供了boost::value_initialized的解决方案 链接,但我相信VC12(VS2013)现在有更好的支持。 - v.oddou
1
让我希望委员会将标准更改为默认值初始化并在请求时削弱价值。即 std::array<int, 12> = {std::undetermined}; 或类似的东西。 - Viktor Sehr
2
@Andrew 另一种选择是它不仅初始化为定义的值。基本上,编译器可以自由地做任何方便的事情。实际上,这通常意味着在调试模式下,您将获得特定的奇怪非零值,在发布模式下,您将获得从其他函数留在该堆栈空间中的任何垃圾(或偶尔的零巧合) - 也就是说,编译器根本不进行初始化。至于为什么要这样做:它更快 - 只要您承诺在尝试读取之前写入其他值。 - Miral
1
@user 这是一个错误;本意应该是 plain_int。已修正。 - Casey
显示剩余6条评论

35
默认初始化是标准中可能意味着根本没有初始化的术语,因此您可能指的是零初始化

cppreference.com上的描述实际上有点误导。 std :: array 是一个聚合类,如果元素类型是基元类型,则它是POD:“ plain old data”,其语义与C语言非常接近。 std :: array <int,N> 的隐式定义构造函数是平凡的,它什么也不做。

std :: array <int,3>() std :: array <int,3> x {} 这样提供零值的语法并没有通过调用构造函数来实现。获得零是值初始化的一部分,在C ++ 11 §8.5 / 8中指定:

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

—如果T是一个(可能是cv限定的)类类型,没有用户提供的或删除的默认构造函数,则对象将被零初始化…,如果T具有非平凡的默认构造函数,则对象将被默认初始化;

std :: array 没有用户提供的默认构造函数,因此它被零初始化。它有一个隐式定义的默认构造函数,但它是平凡的,因此永远不会被默认初始化。 (但这没有关系,因为按定义平凡初始化在运行时不起作用。)

如果没有,是否有一种语法可以在所有数组(包括零大小的数组)上工作,以将所有元素初始化为其默认值?

C风格数组和std :: array 都是聚合体,完全将任何聚合体归零的方法是使用语法 = {} 。自C ++ 98以来,这就起作用了。请注意,C风格数组不能具有零范围,并且 sizeof(std :: array <X,0>)不为零。


“std::array<int, 3>()或std::array<int, 3> x {}这样的语法提供了零值,但它们并不是通过调用构造函数来实现的。” 这是什么意思?您想告诉我们什么?您能否详细解释一下? - John

15

T x[N];std::array<T, N> x; 都会对数组的每个元素进行默认初始化。

例如,如果 T = std::string,则每个元素都将是一个空字符串。如果 T 是一个没有默认构造函数的类,则两者都无法编译通过。如果 T = int,则除非该声明发生在命名空间范围内,否则每个元素都将具有不确定的值。


3
你的例子非常详细,应该成为被接受的答案的一部分。 - Antonio

5

0
首先,T x[N]确实会默认初始化元素,尽管标量类型T的默认初始化实际上什么也不做。对于std::array x也是如此。我认为你需要的是列表初始化。

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