【问题标题】:What is the order of subobject initialization?子对象初始化的顺序是什么?
【发布时间】:2014-08-13 04:27:55
【问题描述】:

让我们有一个类的对象o,它包含另一个类类型的成员子对象sosso。考虑以下示例:

#include <iostream>
using namespace std;
    struct SO{ SO(){ cout << "SO()" << endl; } };
    struct SSO{ SSO(){ cout << "SSO()" << endl; } };

        struct O
        {
            O(){ cout << "O()" << endl; }
            SO so;
            SSO sso;
        };
    int main()
    {
        O o = *(new O);
    }

输出:

SO()

SSO()

O()

demo

第 5.3.4 节所述:

创建 T 类型对象的 new 表达式初始化 对象如下:

——如果省略了 new-initializer,则对象为 默认初始化(8.5);如果不执行初始化,则 对象具有不确定的价值。

——否则,新的初始化器是 根据 8.5 的初始化规则解释 直接初始化。

在特定情况下,对象o 会执行默认初始化(即构造函数调用)。但是他的子对象呢?似乎也执行了默认初始化。但是在标准中哪里规定了如果任何子对象的完整对象被默认初始化,则对它们执行默认初始化?

【问题讨论】:

  • o 的声明是一种立即泄漏内存的好方法。无论如何,你想要 [class.base.init]。

标签: c++ initialization


【解决方案1】:

说对对象o 执行默认初始化是不正确的。在您的示例对象中,o 是复制初始化的。您的示例中的默认初始化是针对 new 创建的未命名对象执行的(随后会泄露)。

现在,由new 创建的O 类型的未命名对象确实是默认初始化的,在这种情况下,这意味着它是通过调用用户定义的默认构造函数O::O() 来初始化的。 O::O() 构造函数中的构造函数初始化列表完全不存在,即没有提及任何子对象。这意味着这些子对象将被默认初始化。

如中所述

12.6.2 初始化基和成员

8 在非委托构造函数中,如果给定的非静态数据成员或 基类不是由 mem-initializer-id 指定的(包括 没有 mem-initializer-list 的情况,因为构造函数 没有 ctor-initializer) 并且实体不是 一个抽象类(10.4),然后

——如果实体是非静态数据 brace-or-equal-initializer 的成员,实体是 按照 8.5 中的规定进行初始化;

——否则,如果实体是 变体成员(9.5),不执行初始化;

——否则, 实体是默认初始化的 (8.5)。

最后一个选项适用于您的情况。 (由于我使用的是文档的草稿版本,因此编号可能已关闭。)

请注意,您的问题标题提到了“子对象初始化的顺序”,而实际问题与顺序本身无关。就是关于初始化的方法。

【讨论】:

  • 这正是我一直在寻找的。谢谢。
【解决方案2】:

§12.6.2/10

在非委托构造函数中,初始化按以下顺序进行:

  • 首先,并且仅对于最派生类 (1.8) 的构造函数,虚拟基类在 它们出现在基类的有向无环图的深度优先从左到右遍历中的顺序, 其中“从左到右”是派生类base-specifier-list中基类的出现顺序。
  • 然后,直接基类按照它们出现在基说明符列表中的声明顺序进行初始化 (不考虑 mem-initializers 的顺序)。
  • 然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样与 mem-initializers 的顺序无关)。
  • 最后,构造函数体的compound-statement被执行。

因此:无论选择哪个构造函数进行初始化——默认或其他,显式默认或用户提供——首先初始化虚拟基类,然后初始化直接基类(按照它们的顺序)出现在 base-specifier-list 中,正如它所说的那样——而不是按照它们出现在 ctor-initializer 中的顺序);最后按声明顺序初始化非静态数据成员子对象。

【讨论】:

    【解决方案3】:

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

    • 如果 T 是(可能是 cv 限定的)类类型(第 9 条),则调用 T 的默认构造函数...

    【讨论】:

    • 这不是一个答案,因为我对 subobject 的初始化很感兴趣
    • 默认的构造函数,当然是初始化对象的子对象。我计划做到这一点,但@AndreyT 打败了我。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-10
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多