Что означают следующие слова в С++: нуль, инициализация по умолчанию и значение?

Что означают следующие слова в С++:

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

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

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

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

Ответ 1

Необходимо понять, что "инициализация значения" является новой для стандарта 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 <cstdio>
#include <cstring>
#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)];
    std::memset( buf, 0x5a, sizeof( buf));

    // use placement new on the memset'ed buffer to make sure 
    //  if we see a zero result it 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
    std::printf( "m  is %d\n", pB->m);
    return 0;
}

Ответ 2

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

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

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

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

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