初始化列表中的依赖关系

Posted

技术标签:

【中文标题】初始化列表中的依赖关系【英文标题】:Dependencies in Initialization Lists 【发布时间】:2011-09-11 07:32:33 【问题描述】:

这种行为是否明确定义?

class Foo

    int A, B;

    public:

    Foo(int Bar): B(Bar), A(B + 123)
    
    
;

int main()

    Foo MyFoo(0);
    return 0;

【问题讨论】:

【参考方案1】:

不,它是未定义的。 A 将首先被初始化(它在类定义中的第一个),它使用未初始化的B

类成员按照它们在类定义中出现的顺序进行初始化,与它们在初始化列表中的顺序无关。实际上,将成员定义顺序与初始化列表顺序不匹配是不好的做法。

如果您的 Foo 实例恰好具有静态持续时间,例如在 Foo f(0); int main() 中,则行为是明确定义的。具有静态持续时间的对象在任何其他初始化发生之前被初始化为零;在这种情况下,AB 在构造函数运行时将为 0。但是,之后的行为是相同的:首先是A,然后是B,给A 赋值123,给B 赋值Bar(仍然丑陋)。

【讨论】:

确实如此。编写构造函数的最佳方式是Foo(int Bar): A(Bar + 123), B(Bar) 注意:如果初始化列表没有按照它们在类/结构中声明的相同顺序列出属性,gcc(至少)会发出警告。 @Matthieu 是的,但这需要启用-Wextra @Maxpm:我认为-Wall 就足够了,尽管我同意如果它默认处于活动状态会很棒。【参考方案2】:

初始化是按照在声明中出现的顺序进行的,而不是你在构造函数中写的顺序。

看这个问题,有点类似: Initializer list *argument* evaluation order

【讨论】:

【参考方案3】:

不,初始化顺序由类本身的声明顺序定义。

来自 C++ 标准12.6.2 [class.base.init] p5

初始化应按以下顺序进行: — 首先,并且仅对于如下所述的最派生类的构造函数,虚拟基类应按照它们在基类的有向无环图的深度优先从左到右遍历中出现的顺序进行初始化,其中“从左到右”是派生类基说明符列表中基类名称的出现顺序。 — 然后,直接基类应按照它们出现在 base-specifier-list 中的声明顺序进行初始化(无论 mem-initializers 的顺序如何)。— 然后,非静态数据成员应在它们在类定义中声明的顺序(同样与 mem-initializers 的顺序无关)。 — 最后,构造函数的主体被执行。 [注意:声明顺序是为了确保基子对象和成员子对象以初始化的相反顺序被销毁。 ]

【讨论】:

以上是关于初始化列表中的依赖关系的主要内容,如果未能解决你的问题,请参考以下文章

C++ 中的循环依赖

依赖项没有复制 ctor 或赋值运算符时的 C++ 初始化程序列表

react组件初始化接口请求有多个异步依赖参数

面向对象程序设计-C++_课时16子类父类关系

第46课 继承中的构造与析构

为啥初始化列表允许 C++ 中的类型缩小?