Почему POD в структуре инициализируется нулем неявным конструктором при создании объекта в куче или временного объекта в стеке?

Стандарт и книга C++ говорят, что конструктор по умолчанию для членов типа класса вызывается неявным сгенерированным конструктором по умолчанию, но встроенные типы не инициализируются. Тем не менее, в этой тестовой программе я получаю неожиданные результаты при выделении объекта в куче или при использовании временного объекта:

#include<iostream>


struct Container
{
    int n;
};

int main()
{
    Container c;
    std::cout << "[STACK] Num: " << c.n << std::endl;

    Container *pc = new Container();
    std::cout << "[HEAP]  Num: " << pc->n << std::endl;
    delete pc;

    Container tc = Container();
    std::cout << "[TEMP]  Num: " << tc.n << std::endl;

}

Я получаю этот вывод:

[STACK] Num: -1079504552
[HEAP]  Num: 0
[TEMP]  Num: 0

Это поведение компилятора? Я не собираюсь на это полагаться, но мне любопытно узнать, почему это происходит, особенно для третьего случая.

2 ответа

Решение

Это ожидаемое поведение. Есть две концепции: "инициализация по умолчанию" и "инициализация значения". Если вы не упоминаете никакой инициализатор, объект "инициализируется по умолчанию", в то время как если вы упоминаете об этом, даже как () для конструктора по умолчанию, объект "инициализируется значением". Когда конструктор определен, оба случая вызывают конструктор по умолчанию. Но для встроенных типов "инициализация значения" обнуляет память, тогда как "инициализация по умолчанию" - нет.

Итак, когда вы инициализируете:

Type x;

он будет вызывать конструктор по умолчанию, если он указан, но примитивные типы будут неинициализированы. Однако, когда вы упоминаете инициализатор, например,

Type x = {}; // only works for struct/class without constructor
Type x = Type();
Type x{}; // C++11 only

примитивный тип (или примитивные члены структуры) будет инициализирован VALUE.

Аналогично для:

struct X { int x; X(); };

если вы определите конструктор

X::X() {}

член x будет неинициализирован, но если вы определите конструктор

X::X() : x() {}

это будет VALUE-инициализировано. Это относится к new ну так вот

new int;

должен дать вам неинициализированную память, но

new int();

должен дать вам память инициализируется до нуля. К сожалению, синтаксис:

Type x();

не допускается из-за неясности грамматики и

Type x = Type();

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

C++ 11 вводит новый синтаксис,

Type x{};

который можно использовать в обоих случаях. Если вы все еще придерживаетесь более старого стандарта, вот почему есть Boost.ValueInitialized, так что вы можете правильно инициализировать экземпляр аргумента шаблона.

Более подробное обсуждение можно найти, например, в документации Boost.ValueInitialized.

Краткий ответ: пустые скобки выполняют инициализацию значения.

Когда ты сказал Container *pc = new Container; вместо этого вы будете наблюдать другое поведение.

Другие вопросы по тегам