考虑以下代码,其中我们基于D
的另一部分初始化D
的一部分:
struct c {
c() : D{rand(), D[0]} {}
int D[2];
};
int main() {
c C;
assert(C.D[0] == C.D[1]);
}
上述程序是否定义明确?我们可以安全地使用同一数组的一部分来初始化它的另一部分吗?
当聚合(包括数组(从大括号列表初始化时,每个聚合元素都从列表的相应元素初始化("按下标或成员顺序递增"(。尽管我找不到一个确切的规则来说明每个元素初始化都是在前一个元素初始化之后排序的,但标准中有一个例子清楚地暗示这是预期的含义。示例在 [dcl.init.aggr] 中:
struct S { int a; const char* b; int c; int d = b[a]; }; S ss = { 1, "asdf" };
用
1
初始化ss.a
,用"asdf"
ss.b
初始化,ss.c
用形式int{}
(即0
(的表达式的值初始化,用ss.b[ss.a]
的值(即’s’
(初始化ss.d
数组成员可以自引用初始化吗?
是的。
struct c {
int a[3];
c() : a{4, a[0], 3} {} // a[0] is initialized to 4.
// a[1] is initialized to whatever a[0] is. (4)
// a[2] is initialized to 3.
};
但请考虑以下示例:
struct c {
int a[3];
c() : a{a[1], 4, a[1]} {} // a[0] is initialized to whatever a[1] is.(Garbage value)
// a[1] is initialized to 4.
// a[2] is initialized to what a[1] is now (4).
};
这里a
的第一个元素将是a[1]
中的任何值, 这很可能是垃圾值。 第二个元素初始化为 4
第三个元素初始化 到现在在a[1]
,这是值4
。
另外,当您没有列出{}
内数组中的所有元素时, 未列出的元素将默认初始化:
struct c {
int a[5]; // notice the size
c() : a{a[1], 2, 3, 4}{} // a[0] will get value that is in a[1]
// but since a[1] has garbage value,
// it will be default initialized to 0.
// a[1] = 2
// a[2] = 3
// a[3] = 4
// a[4] is not listed and will get 0.
};
但是,列出已初始化的元素将为您提供所需的值。
使用上面的例子:
struct c {
int a[5];
c() : a{1, a[0], 3, 4}{} // a[0] = 1
// a[1] = 1
// a[2] = 3
// a[3] = 4
// a[4] is not listed and will get 0.
};
根据 cppreference.com:
聚合初始化的效果包括:
每个数组元素或非静态类成员,按数组顺序排列 类定义中的下标/外观,从 初始值设定项列表的相应子句。
您的代码似乎很好。然而,这在某种程度上令人困惑。
写
D{rand(),D[0]}
不是一个好习惯,因为当 构造函数将运行,第一个 rand(( 不一定是 然后执行 D[0],这完全取决于编译器,D[0] 可能是 首先执行,在这种情况下 d[1] 将包含垃圾值。它 完全取决于编译器,它可以编译第二个参数 首先是第一个参数,反之亦然,执行此参数 语句可能会导致未知行为。