Рассмотрим следующий код, в котором мы инициализируем часть D
основанный на другой части D
:
struct c {
c() : D{rand(), D[0]} {}
int D[2];
};
int main() {
c C;
assert(C.D[0] == C.D[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.
};
Когда агрегаты (включая массивы) инициализируются из фигурного списка, каждый элемент агрегата инициализируется из соответствующего элемента списка («в порядке возрастания индекса или порядка элементов»). Несмотря на то, что я не могу найти точное правило, которое говорит, что инициализация каждого элемента выполняется после предыдущей, в Стандарте есть пример, который явно подразумевает, что это подразумеваемое значение. Пример находится в [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’
)
В соответствии с cppreference.com:
Эффекты инициализации агрегата:
Каждый элемент массива или нестатический член класса, в порядке массива
индекс / внешний вид в определении класса, инициализируется копией из
соответствующий пункт списка инициализаторов.
Ваш код кажется в порядке.
Однако как-то сбивает с толку.
Это не очень хорошая практика, чтобы писать
D{rand(),D[0]}
потому что когда
конструктор будет запускаться не обязательно, что первый rand () будет
затем выполняется D [0], все зависит от компилятора, D [0] может быть
выполняется первым, в этом случае d [1] будет содержать значение мусора. Это
полностью зависит от компилятора, он может скомпилировать второй аргумент
сначала, а затем первый аргумент или наоборот, выполняя это
утверждение может привести к неизвестному поведению.