Подтвердить что ты не робот

Могут ли элементы массива инициализироваться самостоятельно?

Рассмотрим следующий код, в котором мы инициализируем часть D на основе другой части D:

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

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

Является ли указанная выше программа корректной? Можем ли мы безопасно использовать одну часть того же массива для инициализации другой части?

4b9b3361

Ответ 1

Можно ли инициализировать элементы массива самостоятельно?

Да.

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

Ответ 2

Когда агрегаты (включая массивы) инициализируются из скопированного списка, каждый элемент агрегата инициализируется из соответствующего элемента списка ( "в возрастающем индексе или порядке члена" ). Несмотря на то, что я не могу найти точное правило, в котором говорится, что каждая инициализация элемента секвенирована после предыдущего, есть пример в Стандарте, который ясно подразумевает, что это предназначенный смысл. Пример приведен в [dcl.init.aggr]:

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

инициализирует ss.a с помощью 1, ss.b с "asdf", ss.c со значением выражения формы int{} (т.е. 0) и ss.d с значение ss.b[ss.a] (то есть ’s’)

Ответ 3

Согласно cppreference.com:

Эффекты агрегатной инициализации:

Каждый элемент массива или нестатический член класса, в порядке массива индекс/внешний вид в определении класса, копируется с соответствующий раздел списка инициализаторов.

Ваш код кажется прекрасным. Однако как-то запутанно.

Ответ 4

Неправильно писать D{rand(),D[0]}, потому что, когда конструктор будет работать, не обязательно, чтобы первый rand() был выполняется D [0], все зависит от компилятора, D [0] может быть сначала выполняется, в этом случае d [1] будет содержать значение мусора. Это полностью зависит от компилятора, он может скомпилировать второй аргумент сначала, а затем первый аргумент или наоборот, выполнение этого может привести к неизвестному поведению.