在下面的代码片段中,d1的初始化程序是d2,它还没有被构造(正确吗?),D的复制构造函数中的d.j是未初始化的内存访问吗?
struct D
{
int j;
D(const D& d) { j = d.j; }
D(int i) { j = i; }
};
struct A
{
D d1, d2;
A() : d2(2), d1(d2) {}
};
C ++标准的哪一部分讨论了数据成员的初始化顺序?
答案 0 :(得分:11)
我现在没有标准的方便所以我不能引用该部分,但结构或类成员初始化总是按声明的顺序发生。构造函数初始化列表中提到成员的顺序不相关。
Gcc有一个警告-Wreorder
,当订单不同时会发出警告:
-Wreorder (C++ only) Warn when the order of member initializers given in the code does not match the order in which they must be executed. For instance: struct A { int i; int j; A(): j (0), i (1) { } }; The compiler will rearrange the member initializers for i and j to match the declaration order of the members, emitting a warning to that effect. This warning is enabled by -Wall.
答案 1 :(得分:11)
C ++标准(ISO / IEC 14882:2003 12.6.2 / 5,初始化基础和成员)说:
初始化应按以下顺序进行:
- 首先,仅对于如下所述的派生类最多的构造函数,虚拟基类应按它们出现在基类有向无环图的深度优先从左到右遍历的顺序进行初始化。 ,其中“从左到右”是派生中基类名称的出现顺序 class base-specifier-list。
- 然后,直接基类应按声明顺序初始化,因为它们出现在base-specifier-list中(无论mem-initializers的顺序如何)。
- 然后,非静态数据成员应按照在类定义中声明的顺序进行初始化(同样不管mem-initializers的顺序如何)。
- 最后,执行构造函数的主体。
子弹点3保证非静态数据成员初始化的顺序。
答案 2 :(得分:6)
在您的示例中,它将失败:
struct A
{
D d1, d2;
A() : d2(2), d1(d2) {}
};
d1: is initialised first as it is declared first.
d2: is then initialized.
因此,初始化列表将使用对无效对象的引用(d2)构造d1。
这是使编译器警告级别尽可能高的一个原因 另外强制它将所有警告报告为错误。
答案 3 :(得分:2)
在Meyer的 Effective C ++ 的第13项中解释/强调了这种现象。它说析构函数必须按其构造函数的逆序销毁元素,因此所有构造函数必须以相同的顺序初始化元素,因此它们按照它们被声明的顺序(而不是初始化列表的序列)初始化它们
答案 4 :(得分:1)
是。一个好的编译器应警告您A::d2
之后将初始化A::d1
。