Подтвердить что ты не робот

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

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

#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

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

4b9b3361

Ответ 1

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

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

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();

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

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

Type x{};

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

Более подробное обсуждение может быть найдено, например. в Boost.ValueИнализированная документация.

Ответ 2

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

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