Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can array members be initialized self-referentially?

Consider the following code in which we initialize part of D based on another part of D:

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

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

Is the above program well-defined? Can we safely use one part of the same array to initialize another part of it?

like image 670
emlai Avatar asked Jun 27 '15 17:06

emlai


3 Answers

When aggregates (including arrays) are initialized from a braced list, each aggregate element is initialized from the corresponding element of the list ("in increasing subscript or member order"). Even though I can't find an exact rule that says that each element initialization is sequenced after the preceding one, there's an example in the Standard that clearly implies that this is the intended meaning. The example is in [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’)

like image 174
Kerrek SB Avatar answered Oct 07 '22 09:10

Kerrek SB


Can array members be initialized self-referentially?

Yes.

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

But consider this example:

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

Here the first element in a will be whatever value is in a[1], which will most likely be garbage value. Second element is initialized to 4 and third element is initialized to what is now in a[1], which is the value 4.

Also, when you don't list all the elements in the array inside the {}, elements that aren't listed, will be default initialized:

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

However, listing an element already initialized will give you the value you want.
Using above example:

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.
};
like image 43
Andreas DM Avatar answered Oct 07 '22 09:10

Andreas DM


According to 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.

Your code seems fine. However is somehow confusing.

like image 23
masoud Avatar answered Oct 07 '22 11:10

masoud