logo
volkov / C++ / Бьерн Страуструп-Справочное руководство по С++

R.8.4.1 Агрегат

Агрегатом называется массив или объект типа класс ($$R.9), не имеющий

конструкторов ($$R.12.1), частных или защищенных членов ($$R.11),

базовых классов ($$R.10) и виртуальных функций ($$R.10.2). Если

агрегат инициализируется, то инициализатором должен быть

список-инициализаторов, который состоит из заключенного в фигурные

скобки списка, разделенного запятыми, инициализаторов для членов

агрегата. Инициализаторы идут в возрастающем порядке индексов или

членов агрегата. Если агрегат содержит вложенные агрегаты, это

правило применяется рекурсивно для членов вложенных агрегатов. Если

инициализаторов в списке меньше, чем членов агрегата, то он

дополняется нулевыми значениями соответствующих типов.

Например, в следующем фрагменте

struct S { int a; char* b; int c; }

S ss = { 1, "asdf" };

ss.a инициализируется значением 1, ss.b - "asdf", а ss.c - 0.

Кроме того, агрегат, являющийся классом, можно инициализировать

объектом этого класса или класса, являющегося общим производным

от него ($$R.12.8).

Фигурные скобки разбираются следующим образом. Если

список-инициализаторов начинается левой фигурной скобкой, то

список инициализаторов, разделенных запятыми, задает

значения членам агрегата, причем считается ошибкой, если

инициализаторов больше, чем членов. Иначе, если список-инициализаторов

или вложенный агрегат не начинается левой фигурной скобкой, то

из списка используется такое число элементов, которое нужно для

инициализации членов текущего агрегата; все оставшиеся элементы

используются для инициализации членов следующего агрегата, в который

вложен текущий агрегат.

Например, в определении

int x[] = { 1, 3, 5 };

массив x инициализируется как одномерный массив из трех элементов,

поскольку размер массива не указан, и приведено три инициализатора.

Приведем пример инициализации с полной скобочной структурой.

float y[4][3] = {

{ 1, 3, 5 },

{ 2, 4, 6 },

{ 3, 5, 7},

};

Здесь значения 1, 3, 5 инициализируют первую строку массива y[0],

т.е. y[0][0], y[0][1] и y[0][2]. Аналогично, следующие две строки

инициализируют y[1] и y[2]. Инициализаторы приведены не полностью,

поэтому y[3] инициализируется нулями. Точно такого же результата

можно достичь с помощью такой инициализации:

float y[4][3] = {

1, 3, 5, 2, 4, 6, 3, 5, 7,

};

Последний (самый правый) индекс изменяется быстрее всего.

В последнем примере инициализатор для y начинается левой фигурной

скобкой, но для y[0] скобки не задано, поэтому из списка используется

три элемента, также по три последовательных элемента используется для

y[1] и y[2]. В следующем примере

float y[4][3] = {

{ 1 }, { 2 }, { 3 }, { 4 }

};

инициализируется первый столбец y (который рассматривается как

двумерный массив), а остальные столбцы принимают значение 0.

Инициализация массива объектов типа класс с помощью конструкторов

описывается в $$R.12.6.1.

Инициализатор для объединения без конструктора должен быть

или отдельным выражением типа объединения, или заключенным в фигурные

скобки, инициализатором первого члена объединения, например,

union u { int a; char* b; };

u a = { 1 };

u b = a;

u c = 1; // ошибка

u d = { 0, "asdf" }; // ошибка

u e = { "asdf" }; // ошибка

Число инициализаторов не должно превышать числа членов или

элементов, которые инициализируются. Например, следующая

инициализация ошибочна:

char cv[4] = { 'a', 's', 'd', 'f', 0 }; // ошибка