Пространства имён
Варианты
Действия

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

Материал из cppreference.com
< cpp‎ | language
 
 
 
 

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

Содержание

[править] Синтаксис

T объект ;(1)
new T(2)

[править] Объяснение

Инициализация по умолчанию выполняется в трёх случаях:

1) когда переменная с автоматической, статической или потоковой длительностью хранения объявлена без инициализатора;
2) когда объект с динамической длительностью хранения создаётся с помощью выражения new без инициализатора;
3) когда базовый класс или нестатический элемент данных не упоминается в списке инициализаторов конструктора и вызывается этот конструктор.

Эффект инициализации по умолчанию:

  • если T является (возможно cv-квалифицированным) не-POD (до C++11) типом класса, конструкторы рассматриваются и подвергаются разрешению перегрузки с пустым списком аргументов. Выбранный конструктор (который является одним из конструкторов по умолчанию) вызывается для предоставления начального значения для нового объекта;
  • если T является типом массива, каждый элемент массива инициализируется по умолчанию;
  • иначе инициализация не производится (смотрите примечание).

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

Если программа требует инициализации по умолчанию объекта const-квалифицированного типа T, T должен быть константно по умолчанию создаваемым типом класса или его массивом.

Тип класса T является константно по умолчанию создаваемым, если инициализация по умолчанию T вызовет предоставленный пользователем конструктор класса T (не унаследованный от базового класса) (начиная с C++11) или если

Только (возможно, cv-квалифицированные) не-POD типы классов (или их массивы) с автоматической длительностью хранения считались инициализированными по умолчанию, когда не используется инициализатор. Скалярные и POD типы с динамической длительностью хранения считались неинициализированными (начиная с C++11, эта ситуация была переклассифицирована как форма инициализации по умолчанию).

(до C++11)
  • каждый прямой нестатический элемент данных M из T имеет тип класса X (или его массив), где X является константно по умолчанию создаваемым, и
  • T не содержит прямых вариантных элементов, и
(до C++11)
  • каждый прямой невариантный нестатический элемент данных M из T имеет инициализатор элемента по умолчанию или, если M имеет тип класса X (или его массив), тогда X является константно по умолчанию создаваемым,
  • если T является объединением хотя бы с одним нестатическим элементом данных, ровно один вариантный элемент имеет инициализатор элемента по умолчанию,
  • если T не является объединением, для каждого анонимного элемента объединения по крайней мере с одним нестатическим элементом данных (если есть), ровно один нестатический элемент данных имеет инициализатор элемента по умолчанию, и
(начиная с C++11)

каждый потенциально конструируемый базовый класс T является константно по умолчанию создаваемым.

[править] Чтение из неопределённого байта

Использование неопределённого значения, полученного путём инициализации по умолчанию переменной любого типа, не относящейся к классу, является неопределённым поведением (в частности, это может быть представлением ловушкой), за исключением следующих случаев:

  • если неопределённое значение типа unsigned char или std::byte (начиная с C++17) присвоено другой (возможно, cv-квалифицированной) переменной типа unsigned char или std::byte (начиная с C++17) (значение переменной становится неопределённым, но поведение нет);
  • если неопределённое значение типа unsigned char или std::byte (начиная с C++17) используется для инициализации другой (возможно, cv-квалифицированной) переменной типа unsigned char или std::byte (начиная с C++17);
  • если неопределённое значение типа unsigned char или std::byte (начиная с C++17) является результатом
  • второго или третьего операнда условного выражения,
  • правым операндом оператора запятая,
  • операнда приведения или преобразования в (возможно, cv-квалифицированный) unsigned char или std::byte (начиная с C++17),
  • выражения с отброшенным значением.
int f(bool b)
{
    int x;               // OK: значение x неопределено
    int y = x;           // неопределённое поведение
    unsigned char c;     // OK: значение c неопределено
    unsigned char d = c; // OK: значение d неопределено
    int e = d;           // неопределённое поведение
    return b ? d : 0;    // поведение неопределено, если b истинно
}

[править] Примечание

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

Ссылочные и константные скалярные объекты не могут быть инициализированы по умолчанию.

[править] Пример

#include <string>
 
struct T1 { int mem; };
 
struct T2
{
    int mem;
    T2() { } // "mem" отсутствует в списке инициализаторов
};
 
int n; // статическая неклассовая переменная, выполняется двухэтапная инициализация:
       // 1) нулевая инициализация инициализирует n нулём
       // 2) инициализация по умолчанию ничего не делает, оставляя n равным нулю
 
int main()
{
    int n;            // не класс, значение неопределено
    std::string s;    // класс, вызывает конструктор по умолчанию, значение ""
                      // (пустая строка)
    std::string a[2]; // массив, инициализирует элементы по умолчанию, значение
                      // равно {"", ""}
//  int& r;           // ошибка: ссылка
//  const int n;      // ошибка: константа не класс
//  const T1 t1;      // ошибка: константный класс с неявным конструктором по умолчанию
    T1 t1;            // класс, вызывает неявный конструктор по умолчанию
    const T2 t2;      // константный класс, вызывает предоставленный пользователем
                      // конструктором по умолчанию
                      // t2.mem инициализируется по умолчанию (в неопределённое значение)
}

[править] Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

НомерПрименёнПоведение в стандартеКорректное поведение
CWG 178C++98нет инициализации значением; пустой инициализатор вызывает
инициализацию по умолчанию (хотя new T() также выполняет
инициализацию нулём)
пустой инициализатор вызывает
инициализацию значением
CWG 253C++98инициализация константного объекта по умолчанию не могла
вызвать неявно объявленный конструктор по умолчанию
разрешено, если все подобъекты
инициализированы
CWG 616C++98преобразование lvalue в rvalue любого неинициализированного
объекта всегда было неопределённым поведением
неопределённый unsigned char разрешён
CWG 1787C++98чтение из неопределённого unsigned char, кэшированного в
регистре, было неопределённым поведением
сделано чётко определённым

[править] Смотрите также