Инициализация по умолчанию типов POD в C++
Я знаю, что некоторые переменные POD инициализируются по умолчанию, но другие нет. (Типы POD включают int
, float
, указатели, объединения, массивы типов POD, структуры типов POD и т. д.)
Как область и класс хранения влияют на инициализацию по умолчанию типов POD?
В частности, что из следующего будет неявно инициализировано:
- Локальные переменные с автоматическим хранением
- Статические локальные переменные
- Статические глобальные переменные
- Внешние переменные
- Переменные, выделенные с
new
- POD-члены класса (без явной инициализации в конструкторе)
Я знаю, что существуют некоторые вопросы, касающиеся некоторых из этих ситуаций, но они не являются исчерпывающими (они касаются только конкретных ситуаций).
2 ответа
Локальные переменные с автоматической продолжительностью хранения не инициализируются автоматически. Поскольку использование неинициализированных переменных приводит к неопределенному поведению, хорошей практикой является явная инициализация ваших переменных, даже если они избыточны.
О типах POD, которые инициализируются нулями, стандарт C++03 3.6.2 Инициализация состояний нелокальных объектов:
§1 Объекты со статической продолжительностью хранения (3.7.1) должны быть инициализированы нулями (8.5), прежде чем произойдет любая другая инициализация. Обнуление инициализации и инициализация с постоянным выражением вместе называются статической инициализацией; все остальные инициализации - это динамическая инициализация. Объекты типов POD (3.9) со статической продолжительностью хранения, инициализированные с помощью константных выражений (5.19), должны быть инициализированы перед любой динамической инициализацией.
Таким образом, согласно стандарту гарантируется, что типы POD со статической продолжительностью хранения (независимо от их объема) будут инициализироваться нулем.
POD-члены класса (без явной инициализации в конструкторе)
Эта ситуация описана в 12.6.2 Инициализация баз и элементов, в которых говорится (выбранные части):
Если данный нестатический элемент данных или базовый класс не назван с помощью mem-initializer-id (включая случай, когда нет mem-initializer-list, потому что конструктор не имеет ctor-initializer), тогда:
- Если объект является нестатическим элементом данных..., а класс объекта является классом, отличным от POD, объект инициализируется по умолчанию (8.5)...
- В противном случае сущность не инициализируется...
После завершения вызова конструктора для класса X, если член X не указан ни в mem-инициализаторах конструктора, ни по умолчанию, ни при инициализации значения, ни при получении значения во время выполнения тела конструктора, член имеет неопределенную ценность.
Пример:
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 !!!
}
Если мы говорим только о 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