Что означают следующие фразы в C ++: инициализация нуля, значения по умолчанию и значения? - PullRequest
174 голосов
/ 23 октября 2009

Что означают следующие фразы в C ++:

  • нулевой инициализации

  • инициализация по умолчанию и

  • значение инициализации

Что должен знать о них разработчик C ++?

Ответы [ 2 ]

84 голосов
/ 23 октября 2009

C ++ 03 Стандарт 8.5 / 5:

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

К инициализация по умолчанию объект типа T означает:
- если T является типом класса, отличным от POD (раздел 9), вызывается конструктор по умолчанию для T (и инициализация является некорректной, если у T нет доступного конструктора по умолчанию);
- если T является типом массива, каждый элемент инициализируется по умолчанию;
- иначе объект инициализируется нулями.

К значение-инициализация объект типа T означает:
- если T является типом класса (раздел 9) с конструктором, объявленным пользователем (12.1), то вызывается конструктор по умолчанию для T (и инициализация некорректна, если у T нет доступного конструктора по умолчанию);
- если T является типом класса без объединения без конструктора, объявленного пользователем, то каждый нестатический член данных и компонент базового класса в T инициализируются значением;
- если T является типом массива, то каждый элемент инициализируется значением;
- иначе объект инициализируется нулями

Программа, которая вызывает инициализацию по умолчанию или инициализацию значения для объекта ссылочного типа, неверна. Если T является cv-квалифицированным типом, cv-неквалифицированная версия T используется для этих определений инициализации нуля, инициализации по умолчанию и инициализации значения.

60 голосов
/ 23 октября 2009

Одна вещь, которую нужно осознать, это то, что «инициализация значения» является новой для стандарта C ++ 2003 - она ​​не существует в исходном стандарте 1998 года (я думаю, что это может быть единственная разница, которая не просто пояснение). См. ответ Кирилла В. Лядвинского для определения прямо из стандарта.

См. Этот предыдущий ответ о поведении operator new для получения подробной информации о различном поведении этих типов инициализации и когда они включаются (и когда они отличаются от c ++ 98 до C ++ 03):

Суть ответа такова:

Иногда память, возвращаемая оператором new, будет инициализирована, и иногда это не будет зависеть от того, является ли тип, который вы обновляете, POD или это класс, который содержит члены POD и использует компилятор сгенерированный конструктор по умолчанию.

  • В C ++ 1998 есть 2 типа инициализации: ноль и по умолчанию
  • В C ++ 2003 был добавлен третий тип инициализации, инициализация значения.

По меньшей мере, это довольно сложно, и когда разные методы работают незаметно.

Обязательно нужно знать, что MSVC следует правилам C ++ 98 даже в VS 2008 (VC 9 или cl.exe версии 15.x).

Следующий фрагмент показывает, что MSVC и Digital Mars следуют правилам C ++ 98, а GCC 3.4.5 и Comeau - правилам C ++ 03:

#include <stdio.h>
#include <string.h>
#include <new>

struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

int main()
{
    char buf[sizeof(B)];
    memset( buf, 0x5a, sizeof( buf));

    // use placement new on the memset'ed buffer to make sure 
    //  if we see a zero result it's due to an explicit 
    //  value initialization
    B* pB = new(buf) B();   //C++98 rules - pB->m is uninitialized
                            //C++03 rules - pB->m is set to 0
    printf( "m  is %d\n", pB->m);
    return 0;
}
...