Выбрать главу
Инициализаторы

Инициализация (initialization) присваивает объекту определенное значение в момент его создания. Используемые для инициализации переменных значения могут быть насколько угодно сложными выражениями. Когда определяется несколько переменных, имена всех объектов следуют непосредственно друг за другом. Таким образом, вполне возможно инициализировать переменную значением одной из переменных, определенных ранее в том же определении.

// ok: переменная price определяется и инициализируется прежде,

// чем она будет использована для инициализации переменной discount

double price = 109.99, discount = price * 0.16;

// ok: Вызов функции applyDiscount() и использование ее возвращаемого

// значения для инициализации переменной salePrice

salePrice = applyDiscount(price, discount);

Инициализация в С++ — на удивление сложная тема, и мы еще не раз вернемся к ней. Многих программистов вводит в заблуждение использование символа = при инициализации переменной. Они полагают, что инициализация — это такая форма присвоения, но в С++ инициализация и присвоение — совершенно разные операции. Эта концепция особенно важна, поскольку во многих языках это различие несущественно и может быть проигнорировано. Тем не менее даже в языке С++ это различие зачастую не имеет значения. Однако данная концепция крайне важна, и мы будем повторять это еще не раз.

Инициализация — это не присвоение. Инициализация переменной происходит при ее создании. Присвоение удаляет текущее значение объекта и заменяет его новым.

Списочная инициализация

Тема инициализации настолько сложна потому, что язык поддерживает ее в нескольких разных формах. Например, для определения переменной units_sold типа int и ее инициализации значением 0 можно использовать любой из следующих четырех способов:

int units_sold = 0;

int units_sold = {0};

int units_sold{0};

int units_sold(0);

Использование фигурных скобок для инициализации было введено новым стандартом. Ранее эта форма инициализации допускалась лишь в некоторых случаях. По причинам, описанным в разделе 3.3.1, эта форма инициализации известна как списочная инициализация (list initialization). Списки инициализаторов в скобках можно теперь использовать всегда, когда инициализируется объект, и в некоторых случаях, когда объекту присваивается новое значение.

При использовании с переменными встроенного типа эта форма инициализации обладает важным преимуществом: компилятор не позволит инициализировать переменные встроенного типа, если инициализатор может привести к потере информации:

long double ld = 3.1415926536;

int a{ld}, b = {ld}; // ошибка: преобразование с потерей

int с(ld), d = ld;   // ok: но значение будет усечено

Компилятор откажет в инициализации переменных а и b, поскольку использование значения типа long double для инициализации переменной типа int может привести к потере данных. Как минимум, дробная часть значения переменной ld будет усечена. Кроме того, целочисленная часть значения переменной ld может быть слишком большой, чтобы поместиться в переменную типа int.

То, что здесь представлено, может показаться тривиальным, в конце концов, вряд ли кто инициализирует переменную типа int значением типа long double непосредственно. Однако, как представлено в главе 16, такая инициализация может произойти непреднамеренно. Более подробная информация об этих формах инициализации приведена в разделах 3.2.1 и 3.3.1.

Инициализация по умолчанию

При определении переменной без инициализатора происходит ее инициализация по умолчанию (default initialization). Таким переменным присваивается значение по умолчанию (default value). Это значение зависит от типа переменной и может также зависеть от того, где определяется переменная.

Значение объекта встроенного типа, не инициализированного явно, зависит от того, где именно он определяется. Переменные, определенные вне тела функции, инициализируются значением 0. За одним рассматриваемым вскоре исключением, определенные в функции переменные встроенного типа остаются неинициализированными (uninitialized). Значение неинициализированной переменной встроенного типа неопределенно (см. раздел 2.1.2). Попытка копирования или получения доступа к значению неинициализированной переменной является ошибкой.