Инициализация по умолчанию типов POD в С++

Я знаю, что некоторые переменные POD по умолчанию инициализируются, а другие - нет. (Типы POD включают int, float, указатели, объединения, массивы типов POD, структуры типов POD и т.д.)

Как класс и класс хранения влияют на инициализацию типов POD по умолчанию?

В частности, какое из следующего будет инициализировано неявно:

  • Локальные переменные с автоматическим хранилищем
  • Статические локальные переменные
  • Статические глобальные переменные
  • Внешние переменные
  • Переменные, выделенные с помощью new
  • Элементы POD класса (без явной инициализации в конструкторе)

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

Ответ 1

Локальные переменные с автоматическим временем хранения не инициализируются автоматически. Поскольку использование неинициализированных переменных приводит к undefined поведению, это хорошая практика для явной инициализации ваших переменных, даже когда она избыточна.

О типах POD, которые ноль инициализируются, стандарт С++ 03 3.6.2 Инициализация нелокальных объектов:

§1 Объекты с статической продолжительностью хранения (3.7.1) должны быть с нулевой инициализацией (8.5), прежде чем произойдет любая другая инициализация, Нулевая инициализация и инициализация с постоянным выражением коллективно называются статической инициализацией; вся другая инициализация - это динамическая инициализация. Объекты типов POD (3.9) со статической продолжительностью хранения, инициализированными постоянными выражениями (5.19), должны быть инициализированы до начала любой динамической инициализации.

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

Члены класса POD (без явной инициализации в конструкторе)

Эта ситуация описана в 12.6.2 Инициализация баз и членов, которая заявляет (выбранные части):

Если данный нестатический член данных или базовый класс не назван идентификатором mem-initializer (включая случай, когда нет списка mem-initializer, поскольку у конструктора нет ctor-инициализатора), тогда:

- Если объект является членом нестатических данных..., а класс сущности - класс не-POD, объект инициализирован по умолчанию (8.5)...

- В противном случае объект не инициализируется...

После того как вызов конструктора для класса X завершился, если член X не указан в инициализаторах инициализаторов конструкторов, ни инициализирован по умолчанию, ни инициализирован по значению, ни задан значение во время выполнения тела конструктор член имеет неопределенное значение.

Пример:

class C
{
public:
    C(int x, int z) : x(x), z(z) { }
    int x, y, z;
};

int main(void)
{
    C* c = new C(1,3);
    std::cout << c->y; // value of y is undetermined !!!
}

Ответ 2

Если мы говорим только о POD, то только локальная и глобальная статика и внешние переменные, потому что они должны быть где-то определены.

POD, выделенные с помощью new, также инициализируются иногда - если вы сделаете инициализацию явной:

int* x = new int();

создаст int, инициализированный на 0, с помощью x, указывающий на него, тогда как

int* x = new int;

будет иметь x указывает на неинициализированный int.

Иногда - члены класса POD - они могут быть инициализированы явно (без использования в конструкторе):

struct X
{
   int x;
};

X x;        //x.x is not initialized
X y = X();  //y.x is 0