【问题标题】:array initialisation数组初始化
【发布时间】:2009-10-27 01:38:22
【问题描述】:

我很确定内置类型的数组是未初始化的,而 UDT 的数组是默认初始化的。

int foo[5]; // will contain junk
Foo foo[5]; // will contain 5 Foo objects that are default initialized

无论数组是在堆栈还是堆上分配,都会发生这种情况。

但是,我发现很难找到这方面的权威来源。 Bjarne 指出:

“数组和结构的成员是否默认初始化取决于数组或结构是否是静态的”这并不能告诉我太多。

我也尝试在标准中找到一些东西,但到目前为止无济于事。

有没有人知道权威来源来证实上述内容?

【问题讨论】:

  • Foo 的示例取决于 Foo 是什么 - 如果它是 POD 结构(例如 struct Foo { int x; }),它不会被默认初始化。

标签: c++ arrays initialization


【解决方案1】:

ISO C++03 具有权威性:

POD-struct 是一个聚合类,它没有非 POD-struct、非 POD-union(或此类类型的数组)或引用类型的非静态数据成员,并且没有用户定义的复制分配运算符并且没有用户定义的析构函数。类似地,POD 联合是一个聚合联合,它没有非 POD 结构、非 POD 联合(或此类类型的数组)或引用类型的非静态数据成员,并且没有用户定义的复制赋值运算符并且没有用户定义的析构函数。 POD 类是一个 POD-struct 或 POD-union 的类。

算术类型 (3.9.1)、枚举类型、指针类型和指向成员类型的指针 (3.9.2) 以及这些类型的 cv 限定版本 (3.9.3) 统称为标量类型。标量类型、POD-struct 类型、POD-union 类型(第 9 条)、此类类型的数组以及这些类型的 cv 限定版本 (3.9.3) 统称为 POD 类型。

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

  • 如果 T 是标量类型(3.9),则将对象设置为值 0(零)转换为 T;
  • 如果 T 是非联合类类型,则每个非静态数据成员和每个基类 子对象是零初始化的;
  • 如果 T 是联合类型,则对象的第一个命名数据成员为零初始化;
  • 如果 T 是数组类型,则每个元素都初始化为零;
  • 如果 T 是引用类型,则不执行初始化。

默认初始化 T 类型的对象意味着:

  • 如果 T 是非 POD 类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化格式错误);
  • 如果 T 是数组类型,则每个元素都是默认初始化的;
  • 否则,对象被零初始化。

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

  • 如果 T 是具有用户声明的构造函数 (12.1) 的类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化格式错误);李>
  • 如果 T 是没有用户声明的构造函数的非联合类类型,则 T 的每个非静态数据成员和基类组件都是值初始化的;
  • 如果T是数组类型,那么每个元素都是值初始化的;
  • 否则,对象被零初始化

在任何其他初始化发生之前,每个静态存储持续时间的对象都应在程序启动时进行零初始化。 [注意:在某些情况下,稍后会进行额外的初始化。]

初始化器为空括号集的对象,即 (),应进行值初始化。

如果没有为对象指定初始化器,并且对象是(可能是 cv 限定的)非 POD 类类型(或其数组),则该对象应默认初始化;如果对象是 const 限定类型,则基础类类型应具有用户声明的默认构造函数。否则,如果没有为非静态对象指定初始化器,则该对象及其子对象(如果有)具有不确定的初始值);如果对象或其任何子对象是 const 限定类型,则程序是非良构的。

对于您的示例,int 绝对是 POD 类型(它是算术类型),因此在没有初始化程序的情况下,int 类型的本地或字段将具有不确定的值。对于Foo,这取决于它是如何定义的——粗略地说,如果它没有构造函数,并且它的所有成员都是POD类型,那么它本身就是一个POD类型,也不会进行初始化。否则,调用默认构造函数。即便如此,这并不意味着 members 已初始化 - 规则是递归的,因此非 POD 类型的 POD 成员不会被初始化,除非该类型的构造函数专门这样做(在其初始化程序中)列表)。

静态变量和字段在所有情况下都将被初始化为零。请注意,这也适用于非 POD - 这意味着类类型的静态变量保证在其构造函数运行之前将所有字段递归设置为 (T)0

默认初始化任何聚合 POD 类型的一个方便技巧是在初始化程序中使用 {} - 请注意,它适用于结构和数组:

char s[10] = {}; // all elements default-initialized
Foo foo = {};    // all fields recursively default-initialized

【讨论】:

  • 这个默认初始化的定义和ccpreference一样吗?因为这里对于默认初始化,他们打算在未指定初始化程序时进行初始化。它说在这种情况下,如果类型既不是非 POD 类也不是数组,则不执行初始化。相反,“默认初始化”下的第三点表示对象是零初始化的。举一个具体的例子,你的规则是否说像int a[5]; 这样的数组默认为零初始化?不是。
【解决方案2】:

它在 C++ 标准中说,在 8.5.9 中:

如果没有指定初始化器 对象,并且对象属于(可能 cv 限定)非 POD 类类型(或 数组),对象应为 默认初始化;如果对象是 const 限定类型, 基础类类型应具有 用户声明的默认构造函数。 否则,如果没有初始化器 为非静态对象指定, 对象及其子对象(如果有), 有一个不确定的初始值。

【讨论】:

    【解决方案3】:

    “数组和结构的成员是否默认初始化取决于数组或结构是否为静态”

    这是权威的,虽然它可能更清楚:

    • 声明为 static 的数组和结构被初始化为零。
    • 内置类型(没有构造函数的类型)的局部数组和结构未初始化。

    【讨论】:

    • "本地数组和结构未初始化。" - 这是不正确的。 POD 类型的本地(和成员!)变量未初始化。非 POD 类型的局部变量和成员变量是默认初始化的。
    • @Pavel Minaev:我会说“太笼统”而不是“不正确”——不过还是不错的;更新以反映您的评论。谢谢!
    猜你喜欢
    • 2020-10-24
    • 1970-01-01
    • 1970-01-01
    • 2021-06-03
    • 2019-11-02
    • 1970-01-01
    • 2017-07-21
    • 2010-09-18
    相关资源
    最近更新 更多