【问题标题】:Initializing an array of zeroes初始化一个零数组
【发布时间】:2016-12-17 23:05:28
【问题描述】:

众所周知,标量数组缺少的初始值设定项默认为零。

int A[5]; // Entries remain uninitialized
int B[5]= { 0 }; // All entries set to zero

但这(下)有保证吗?

int C[5]= { }; // All entries set to zero

【问题讨论】:

标签: c++ arrays initialization language-lawyer


【解决方案1】:

空括号初始化执行数组的聚合初始化:这会导致int 元素的零初始化。

是的,这是有保证的。

【讨论】:

  • int C[5] 不是类类型,所以不进行值初始化,进行聚合初始化。
  • @Holt: 和 ?这会改变结论吗?
  • @Holt 是否是类类型不会影响是否执行聚合初始化。所有数组初始化都是聚合初始化。此外,聚合初始化被定义为没有初始化器的成员被值初始化(这相当于零初始化,对于int
  • @MM int C[5] = {}list initializationT = int[5],按照标准,这将执行聚合初始化,但 初始答案 提到了值初始化,这将如果T 是具有默认构造函数的类类型,则属于这种情况。我只是指出这里发生的是聚合初始化,而不是值初始化。
  • 我一直想知道人们是如何知道这种东西的。我的意思是你怎么知道这个“聚合初始化”?如果我可以问的话,你的消息来源是什么?
【解决方案2】:

是的,根据aggregate initialization的规则,可以保证(数组C的所有元素都是value-initialized,即在这种情况下zero-initialized0)。

(强调我的)

如果初始化子句的数量小于成员and bases (since C++17)初始化列表完全为空,则剩余成员and bases (since C++17)由空列表初始化by their default initializers, if provided in the class definition, and otherwise (since C++14),按照使用通常的列表初始化规则(使用默认构造函数对非类类型和非聚合类执行值初始化,并为聚合执行聚合初始化)。


PS:

int A[5]; // Entries remain uninitialized

“保持未初始化”可能不准确。对于int A[5];A 的所有元素都是default-initialized。如果A 是静态或线程本地对象,则元素将为zero-initialized0,否则什么都不做,它们将是不确定的值。

【讨论】:

  • 感谢您的 PS。
  • 既然你引用了一些正式的规范(实际上你应该说是哪一个),A[5] 正确地是默认初始化的
【解决方案3】:

其实当你说int A[5] = { 0 }; 你是说:将第一个元素初始化为零。由于聚合初始化,所有其他位置都初始化为零。

这一行是让你的数组充满零的真正原因:int A[5] = { };

这就是为什么如果您使用int A[5] = { 1 };,您只会将第一个位置初始化为 1。

【讨论】:

  • 但是 OP 询问空的初始化列表。
  • @songyuanyao 已被其他用户回答。只是让观点更清楚
  • 这应该是正确的答案,因为数组对于初始化列表有不同的行为。
【解决方案4】:

首先,让我们证明为什么下面数组 A 中的每个元素都应该为零

int A[5] = {0};

如何保证?涉及以下标准:

  1. 它是Aggregate initialization,因为它是数组类型,并且它的初始化子句数小于成员数,并且第一个元素被复制初始化为0。

每个直接公共基类、(C++17 起)数组元素或非静态类成员,在类定义中按照数组下标/外观的顺序,是copy-从初始化列表的相应子句初始化

  1. 数组中剩余的元素会按照Aggregate的初始化规则,进行值初始化

如果初始化子句的数量小于成员和基数 (C++17 起) 或初始化器列表完全为空,则剩余的成员和基数 (C++17 起)由它们的默认成员初始化初始化器,如果在类定义中提供,否则 (C++14 起) 根据通常的列表初始化规则(对非类类型执行 值初始化 和具有默认构造函数的非聚合类,以及聚合的聚合初始化)。如果引用类型的成员是这些剩余成员之一,则程序是非良构的。

  1. 根据Value Initialization,剩下的4个元素将进入“零初始化”过程

否则,对象被零初始化。

  1. 根据Zero Initialization,剩余元素的类型是int,是scaler类型,所以剩下的4个元素会被初始化为0

如果 T 是标量类型,则对象的初始值是显式转换为 T 的整数常量零。

  1. 所以 A 中的每个元素都应该为零

证明完成!

最后,让我们证明为什么下面数组 B 中的每个元素都应该为零

int B[5] = {};

是值初始化形式,根据Value Initialization

在所有情况下,如果使用空的大括号 {} 对并且 T 是聚合类型,则执行聚合初始化而不是值初始化。

它将进入上层聚合初始化#2,然后B数组中的每个元素都应该为零。

证明完成!

【讨论】:

  • 正确答案是五年前接受的。
  • 原始答案不能用严格证明来证明,所以不能说所有C/C++编译器都可以保证
  • “不能用严格证明来证明”:这是什么意思?
  • 好的,删除答案?我没有从 C/C++ 规范中找到任何引用来证明相关陈述,然后不能保证,对吧?也许您是 C/C++ 教授,但对于某些人来说,我认为可能需要更多信息并引用 C/C++ 规范来展示编译器级别发生的事情。
  • 别大惊小怪。问题本质上是关于“是 UB 还是不是?”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 2015-02-07
  • 2022-12-18
  • 2011-07-30
  • 2011-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多