Справочное руководство по C++
R.8.4 Инициализаторы.
За описателем может идти начальное значение описываемого идентификатора.
Инициализатор:
= выражение-присваивания.
= { список-инициализаторов , opt }
( список-выражений ).
Список-инициализаторов:
выражение-присваивания.
список-инициализаторов, выражение-присваивания.
{ список-инициализаторов , opt }
Автоматические, регистровые, статические и внешние переменные можно инициализировать произвольными выражениями, содержащими константы и описанные ранее переменные и функции.
Int f(int);
Int a = 2;
Int b = f(a);
Int c(b);
Указатель типа const T*, т.е. указатель на константу T, может инициализироваться указателем типа T*, но инициализация для указателей в обратном порядке незаконна. Объекты типа T можно инициализировать объектами типа T независимо от использования спецификаций const или volatile в типах инициализируемой переменной или инициализатора, например,
Int a;
Const int b = a;
Int c = b;
Const int* p0 = &a;
Const int* p1 =&b;
Int* p2 = &b; // ошибка: указатель без const.
// настраивается на объект const.
Int *const p3 = p2;
Int *const p4 = p1; // ошибка: указатель без const.
// настраивается на объект const.
Const int* p5 = p1;
Здесь причина обеих ошибок одна: если допустить подобную инициализацию, она позволит изменять с помощью указателя без соответствующей спецификации значение чего-то, что было описано как const.
На выражения для стандартных значений параметров накладывается больше ограничений, см. §R.8.2.6.
Инициализация объектов классов с помощью конструкторов описывается в §R.12.6.1. Копирование объектов классов описывается в §R.12.8. Порядок инициализации статических объектов определяется в §R.3.4 и §R.6.7.
Гарантируется, что переменные статического класса памяти (§R.3.5), которые не были инициализированы, в качестве начального значения получат 0, приведенный к нужному типу. То же справедливо для статических членов объектов класса. Начальные значения автоматических и регистровых переменных, которые не были инициализированы, неопределены.
Если инициализатор относится к указателю или объекту арифметического типа, он состоит из одного выражения (возможно в скобках). В качестве начального значения объекта берется значение выражения, происходят такие же преобразования типа, как и в случае присваивания.
Заметим, что поскольку () не является инициализатором, описание.
X a();
Задает не объект a типа класс X, а является описанием функции без параметров, возвращающей X.
Инициализатор для статического члена принадлежит области видимости члена класса, например,
Int a;
Struct X {
static int a;
static int b;
};
Int X::a = 1;
Int X::b = a; // X::b = X::a.
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 {i nt 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}; // ошибка.
R.8.4.2 Символьные массивы.
Массив символов (неважно, знаковых или беззнаковых) можно инициализировать строкой-литералом: символы строки последовательно инициализируют элементы массива. Следующее определение дает пример символьного массива, элементы которого инициализируются строкой:
Char msg[] = "Syntax error on line %s\n";
Заметим, что поскольку '\n' задает один символ, и поскольку добавляется завершающий символ '\0', sizeof(msg) равно 25.
Нельзя задавать больше инициализаторов, чем есть элементов в массиве, поэтому следующий пример ошибочен: здесь нет места для подразумевающегося символа конца строки ('\0'):
Char cv[4] = "asdf"; // ошибка.
R.8.4.3 Ссылки.
Переменная, описанная как T&, т.е. "ссылка на тип T" (§R.8.2.2), должна инициализироваться объектом типа T или объектом, который можно преобразовать к типу T, например,
Void f().
{
int i;
int& r = i; // `r' ссылается на `i'.
r = 1; // `i' принимает значение 1.
int* p = &r; // `p' указывает на `i'.
int& rr = r; // `rr' ссылается на то, на что ссылалось `r',
// т.е. на `i'.
};
Ссылку после инициализации нельзя изменять так, чтобы она обозначала другой объект. Отметим, что инициализация ссылки трактуется совсем не так, как присваивание ссылке. Передача параметра (§R.5.2.2) и операция возврата значения функции (§R.6.6.3) считаются инициализацией.
Инициализатор для ссылки можно опускать только в описании параметра (§R.8.2.5), в описании возвращаемого функцией типа, в описании члена класса при описании самого класса (§R.9.2) и там, где явно использована спецификация extern, например,
Int& r1; // ошибка: нет инициализации.
Extern int& r2; // нормально.
Если инициализатор для ссылки на тип T является адресом типа T или типом, производным от T (§R.10), для которого T служит доступным базовым типом (§R.4.6), ссылка будет обозначать значение, заданное инициализатором. Иначе, в том и только том случае, когда ссылка обозначает объект со спецификацией const, будет создан объект типа T и проинициализирован значением, заданным инициализатором.
Теперь ссылка играет роль имени этого объекта, например,
Double d = 1.0;
Double& rd = d; // rd ссылается на `d'.
Const double& rcd = d; // rcd ссылается на `d'.
Double& rd2 = 1; // ошибка: несоответствие типа.
Const double& rcd2 = 1; // rcd2 ссылается на временный объект.
// со значением `1'.
Ссылку на volatile T можно инициализировать объектом типа volatile T или просто T, но не const T. Ссылку на const T можно инициализировать const T, просто T или чем-то, что можно преобразовать в тип T, но не volatile T. Ссылку на тип T (без const или volatile) можно инициализировать только объектом типа T.
Время жизни временного объекта, созданного при описанной инициализации, определяется текущей областью видимости, в которой он был создан (§R.3.5). Отметим, что ссылку на класс B можно инициализировать объектом класса D при условии, что В является однозначно определенным и доступным базовым классом для D (тогда говорят, что "D есть B"), см. §R.4.7.
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.