【发布时间】:2020-07-18 01:30:55
【问题描述】:
一个有趣的问题是这里一些其他问题的副作用,关于 C 和 C++ 处理方式(非静态存储持续时间)之间可能存在的差异:
int arr[7] = {0};
有人说,在 C++ 中,其他元素不能保证为零,但我不确定我是否同意。
现在 C11 状态,在6.7.9 Initialization /19:
初始化应按初始化器列表顺序进行,为特定子对象提供的每个初始化器都将覆盖先前为同一子对象列出的任何初始化器; 所有未显式初始化的子对象都应隐式初始化,与具有静态存储持续时间的对象相同。
这意味着arr 的其他六个元素将初始化为零(因为static int x; 会将x 初始化为零)。
我不确定 C++ 是否也是这种情况。在 C++20 标准中,9.3.1 Aggregates /3 声明:
当聚合被
9.3.4中指定的初始化列表初始化时,初始化列表中的元素将作为聚合元素的初始化。聚合的显式初始化元素确定如下:(3.1) —(与指定的初始化列表和类无关的东西 - pax)。
(3.2) — 如果初始化器列表是初始化器列表,则聚合的显式初始化元素是聚合的第一个
n元素,其中n是初始化器列表中的元素数。
然后/4 说明显式 初始化如何工作,/5 处理非显式情况:
对于非联合聚合,每个不是显式初始化元素的元素都被初始化如下:
(5.1) — 如果元素具有默认成员初始化程序 (10.3),则从该初始化程序初始化元素。
(5.2) — 否则,如果元素不是引用,则从空的初始化列表 (9.3.4) 复制初始化元素。
(5.3) — 否则,程序格式错误。
在我看来,(5.2) 涵盖了我们的特殊情况,因此我们必须转到 9.3.4 以查看使用空列表 ({}) 初始化的 int 会发生什么。这经历了很多案例,但我相信第一个匹配的是:
(3.11) — 否则,如果初始化列表没有元素,则对象被值初始化。
还有,来自9.3 Initializers /8:
对 T 类型的对象进行值初始化意味着:
(8.1) — 如果 T 是(可能是 cv 限定的)类类型(第 10 条),没有默认构造函数 (10.3.4) 或用户提供或删除的默认构造函数,则该对象是默认的-初始化;
(8.2) — 如果 T 是一个(可能是 cv 限定的)类类型,没有用户提供或删除的默认构造函数,则对象为零初始化并检查默认初始化的语义约束,如果 T有一个重要的默认构造函数,对象是默认初始化的;
(8.3) — 如果 T 是一个数组类型,那么每个元素都是值初始化的;
(8.4) — 否则,对象被零初始化。
因此,8.4 似乎是控制子句,这意味着 C++还将将数组的非显式元素初始化为零。
我的推理正确吗? C++ 会在遇到int arr[7] = {0}; 时将所有元素设置为零吗?
【问题讨论】:
-
"有人说,在 C++ 中,不能保证其他元素为零"这是在哪里说的?
-
int arr[7] = {0};会将第一个元素显式初始化为零,然后编译器将添加代码将其余元素初始化为零。 -
简短回答:是
-
@NicolBolas:重读评论时,他们实际上表示
int arr[n]={value}并不能保证所有元素都是value。所以,它们对于value != 0是正确的,但是由于我是 使用{0}作为初始化列表,我觉得这很奇怪。我只是想澄清一下,因为 ISO C++so 比 ISO C 更令人头疼:-) -
我的理解是“是的”——您对当前(草案?)标准的推理和跟踪似乎是合适的。尽管最近的标准使事情变得更加复杂,但在 1998 年的 C++ 标准中,答案也毫不含糊地“是”——如果后续标准会悄悄地改变这一点,我会感到非常惊讶,因为很多现有代码都会中断。
标签: c++ arrays initialization