Конструктор по умолчанию инициализирует встроенные типы? - PullRequest
159 голосов
/ 10 марта 2010

Инициализирует ли конструктор по умолчанию (созданный компилятором) встроенные типы?

Ответы [ 7 ]

162 голосов
/ 10 марта 2010

Неявно определенный (компилятором) конструктор по умолчанию класса не инициализирует члены встроенных типов.

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

Например, широко распространено неправильное мнение, что для класса C синтаксис C() всегда вызывает конструктор по умолчанию. В действительности, однако, синтаксис C() выполняет так называемую инициализацию значения экземпляра класса. Он будет вызывать конструктор по умолчанию, только если он объявлен пользователем . (Это в C ++ 03. В C ++ 98 - только если класс не POD). Если в классе нет объявленного пользователем конструктора, C() не будет вызывать конструктор по умолчанию, предоставляемый компилятором, а будет выполнять специальный тип инициализации, который вообще не включает конструктор C. Вместо этого он будет непосредственно инициализировать значение каждого члена класса. Для встроенных типов это приводит к нулевой инициализации.

Например, если в вашем классе нет объявленного пользователем конструктора

class C { 
  int x;
};

тогда компилятор неявно предоставит его. Предоставленный компилятором конструктор ничего не будет делать, то есть он не будет инициализироваться C::x

C c; // Compiler-provided default constructor is used
// Here `c.x` contains garbage

Тем не менее, следующие инициализации будут инициализировать нулями x, поскольку они используют явный () инициализатор

C c = C(); // Does not use default constructor for `C()` part
           // Uses value-initialization feature instead
assert(c.x == 0);

C *pc = new C(); // Does not use default constructor for `C()` part
                 // Uses value-initialization feature instead
assert(pc->x == 0);

Поведение инициализатора () в некоторых отношениях отличается от C ++ 98 и C ++ 03, но не в этом случае. Для приведенного выше класса C это будет то же самое: () инициализатор выполняет нулевую инициализацию C::x.

Другим примером инициализации, которая выполняется без использования конструктора, является, конечно, агрегатная инициализация

C c = {}; // Does not use any `C` constructors at all. Same as C c{}; in C++11.
assert(c.x == 0);

C d{}; // C++11 style aggregate initialization.
assert(d.x == 0);
18 голосов
/ 10 марта 2010

Для всех практических целей - нет.


Однако для реализаций, которые технически совместимы со стандартом C ++, ответ таков: это зависит от того, является ли объект POD или нет, и от того, как вы его инициализируете. Согласно стандарту C ++:

MyNonPodClass instance1;//built in members will not be initialized
MyPodClass instance2;//built in members will be not be initialized
MyPodClass* instance3 = new MyPodClass;//built in members will not be initialized
MyPodClass* instance3 = new MyPodClass() ;//built in members will be zero initialized

Однако в реальном мире это не очень хорошо поддерживается, поэтому не используйте его.


Соответствующими частями стандарта являются разделы 8.5.5 и 8.5.7

.
16 голосов
/ 10 марта 2010

Я не совсем уверен, что вы имеете в виду, но:

struct A { int x; };

int a; // a is initialized to 0
A b;   // b.x is initialized to 0

int main() {
    int c;         // c is not initialized
    int d = int(); // d is initialized to 0

    A e;           // e.x is not initialized
    A f = A();     // f.x is initialized to 0
}

В каждом случае, когда я говорю «не инициализировано» - вы можете обнаружить, что ваш компилятор дает ему непротиворечивое значение, но стандарт не требует этого.

Много размахиваем руками, в том числе и я, о том, как встроенные типы «в действительности» имеют конструктор по умолчанию. На самом деле инициализация по умолчанию и инициализация значения являются определенными терминами в стандарте, которые лично мне приходится искать каждый раз. Только классы определены в стандарте, чтобы иметь неявный конструктор по умолчанию.

1 голос
/ 10 марта 2010

Как заявили предыдущие ораторы - нет, они не инициализированы.

Это на самом деле источник действительно странных ошибок, поскольку современные ОС стремятся заполнить вновь выделенные области памяти нулями. Если вы ожидаете этого, это может сработать с первого раза. Однако, поскольку ваше приложение продолжает работать, delete -ing и new -ing объекты, вы рано или поздно окажетесь в ситуации, когда вы ожидаете нули, но ненулевой остаток от более раннего объекта сидит.

Итак, почему же тогда не все new -данные данные распределяются заново? Да, но не всегда из ОС. ОС имеет тенденцию работать с большими кусками памяти (например, 4 МБ за раз), поэтому все крошечные выделения «одно слово здесь три три байта там» и освобождение обрабатываются в пространстве пользователя и, таким образом, не обнуляются.

PS. Я написал «как правило», т. Е. Вы не можете даже положиться на успех в первый раз ...

1 голос
/ 10 марта 2010

В соответствии со стандартом, это не так, если вы явно не инициализируете в списке инициализаторов

0 голосов
/ 10 марта 2010

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

Если вы хотели узнать, установлены ли для них что-то вменяемое, например, 0 для int s, тогда ответ «нет».

0 голосов
/ 10 марта 2010

Нет. Конструктор по умолчанию выделяет память и вызывает конструктор без аргументов любых родителей.

...