Почему POD в структуре инициализируется нулем неявным конструктором при создании объекта в куче или временного объекта в стеке? - PullRequest
29 голосов
/ 08 февраля 2011

Стандарт и книга 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 ]

45 голосов
/ 08 февраля 2011

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

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

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 * 1043.*.

19 голосов
/ 08 февраля 2011

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

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

...