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

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

  • нулевая инициализация,

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

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

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


person Bill    schedule 23.10.2009    source источник
comment
Это связано с (но не идентично) stackoverflow.com/questions/620137/   -  person Steve Jessop    schedule 07.12.2010
comment
Есть больше! Полный список инициализаций: значение, прямая, копия, список (новое введение в C ++ 11), агрегат, ссылка, ноль, константа и значение по умолчанию; en.cppreference.com/w/cpp/language/initialization перечисляет все их с примерами :)   -  person legends2k    schedule 07.05.2013


Ответы (2)


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

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

Суть ответа:

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

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

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

Одна вещь, о которой обязательно нужно знать, - это то, что 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'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
    std::printf( "m  is %d\n", pB->m);
    return 0;
}
person Michael Burr    schedule 23.10.2009
comment
Не то чтобы это важно для int, но m() в третьей строке значение инициализирует m. Важно, если вы измените int m; на B m;. :) - person Johannes Schaub - litb; 23.10.2009
comment
Правильно - A и C в этом примере не используются (они перенесены из другого связанного ответа). Несмотря на то, что C ++ 98 и C ++ 03 используют разную терминологию при описании конструирования A и C, результат одинаков в обоих стандартах. Только struct B приводит к другому поведению. - person Michael Burr; 23.10.2009
comment
Я имел в виду, что если вы измените C на struct C { C() : m() {}; ~C(); B m; };, тогда m.m будет 0. Но если он будет инициализировать m по умолчанию, как вы говорите, C ++ 03, то m.m не будет инициализирован, как в C ++ 98. - person Johannes Schaub - litb; 27.09.2010
comment
Дополнительные интересные комментарии по обработке этой функции в MSVC: stackoverflow.com/questions/3931312/ - person Brent Bradburn; 27.07.2011
comment
Какая инициализация происходит, когда вы объявляете свой тип как локальную переменную, то есть в стеке? - person André Puel; 21.03.2013
comment
Вот отличная ссылка на value-initialization и _ 2_. - person Alexei Sholik; 09.07.2013
comment
g ++ 4.4.7 20120313 для Red Hat 4.4.7-18 инициализирует m значением 0 в вашем примере (компиляция с -std = c ++ 98). - person Jean; 27.04.2018
comment
g ++ 10.2.0 для Ubuntu инициализирует m до 0 с вашим примером (компиляция с -std = c ++ 98), а также - person HEKTO; 18.02.2021

Стандарт 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, для этих определений инициализации нулем, инициализации по умолчанию и инициализации значения используется версия T без квалификации.

person Kirill V. Lyadvinsky    schedule 23.10.2009
comment
Это может быть устаревшим для C ++ 11. cppreference.com заявляет, что инициализация по умолчанию не работает члены с нулевой инициализацией (выполняется только инициализация значения). - person Alexei Sholik; 09.07.2013
comment
@android поднимает важный вопрос, на который я не вижу ответа в другом месте, поэтому я задал новый вопрос. stackoverflow.com/questions/22233148 / - person Adrian McCarthy; 06.03.2014