此行为是否已定义良好?初始化列表中的依赖项
class Foo
{
int A, B;
public:
Foo(int Bar): B(Bar), A(B + 123)
{
}
};
int main()
{
Foo MyFoo(0);
return 0;
}
此行为是否已定义良好?初始化列表中的依赖项
class Foo
{
int A, B;
public:
Foo(int Bar): B(Bar), A(B + 123)
{
}
};
int main()
{
Foo MyFoo(0);
return 0;
}
不,它是未定义的。 A
将首先被初始化(它是类定义中的第一个),它使用未初始化的B
。
类成员将按照它们在类定义中出现的顺序进行初始化,而不管它们在初始化列表中的顺序如何。事实上,将成员定义顺序与初始化列表顺序不匹配是不好的做法。
如果您的Foo
实例恰好具有静态持续时间,例如Foo f(0); int main(){}
,则行为已定义良好。具有静态持续时间的对象在进行任何其他初始化之前是零初始化的;在这种情况下,运行构造函数时,A
和B
将为0。然而,之后,行为是相同的:首先A
然后B
,给A
值123和B
值Bar
(仍然丑陋)。
初始化是按照出现在声明中的顺序完成的,而不是您在构造函数中写入的顺序。
看看这个问题,它有点类似: Initializer list *argument* evaluation order
没有,初始化顺序是由类本身声明顺序定义。
从C++标准12.6.2 [class.base.init] p5
:
初始化按照下列顺序进行:
- 首先,只对最派生类的构造如下所述,虚拟基类应当在初始化它们出现在基类的有向非循环图的深度优先从左到右的遍历中的顺序,其中“从左到右”是派生类中基类名的出现顺序base-specifier-名单。
- 然后,直接基类应按声明顺序进行初始化,因为它们出现在base-specifier-list中(不管mem-initializers的顺序如何)。
- 然后,非静态数据成员应按照它们在类定义中声明的顺序进行初始化(不管mem-initializers的顺序如何)。
- 最后,构造函数的主体被执行。
[注意:声明顺序的任务是确保基本和成员子对象以与初始化相反的顺序销毁。 ]
确实。编写构造函数的最好方法是'Foo(int bar):A(Bar + 123),B(Bar){}'。 – 2011-06-09 01:12:55
注意:如果初始化列表没有按照在类/结构中声明的顺序列出属性,gcc(至少)会发出警告。 – 2011-06-09 06:32:22
@Matthieu是的,但需要启用'-Wextra'。 – Maxpm 2011-06-09 19:30:08