数组成员可以自引用初始化吗?

Can array members be initialized self-referentially?

考虑以下代码,其中我们根据 D 的另一部分初始化 D 的一部分:

struct c {
    c() : D{rand(), D[0]} {}
    int D[2];
};

int main() {
    c C;
    assert(C.D[0] == C.D[1]);
}

上面的程序是否定义明确?我们可以安全地使用同一个数组的一部分来初始化它的另一部分吗?

当从花括号列表初始化聚合(包括数组)时,每个聚合元素都从列表的相应元素初始化 ("in increasing subscript or member order")。尽管我找不到一个确切的规则来说明每个元素初始化都在前一个元素之后进行,但标准中有一个示例清楚地暗示这是预期的含义。示例在 [dcl.init.aggr]:

struct S { int a; const char* b; int c; int d = b[a]; };
S ss = { 1, "asdf" };

initializes ss.a with 1, ss.b with "asdf", ss.c with the value of an expression of the form int{} (that is, 0), and ss.d with the value of ss.b[ss.a] (that is, ’s’)

It is not a good practice to write D{rand(),D[0]}, because when the constructor will run it is not necessary that first rand() will be executed then D[0], it all depends on the compiler, D[0] could be executed first, in that case d[1] will contain garbage value. It completely depends on the compiler, it can compile the second argument first and then the first argument or vice-versa, executing this statement might result in unknown behavior.

根据cppreference.com

The effects of aggregate initialization are:

Each array element or non-static class member, in order of array subscript/appearance in the class definition, is copy-initialized from the corresponding clause of the initializer list.

您的代码看起来不错。 然而有点令人困惑。

Can array members be initialized self-referentially?

是的。

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.
};