Що означають наступні фрази в C ++: ініціалізація нуля, за замовчуванням та значення?


190

Що означають наступні фрази в C ++:

  • нульова ініціалізація,

  • ініціалізація за замовчуванням та

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

Що повинен знати про них розробник C ++?


1
Це пов’язано з (але не ідентично) stackoverflow.com/questions/620137/…
Стів Джессоп

20
Є ще більше! Повний список ініціалізацій: значення, пряма, копія, список (C ++ 11 нове вступ), сукупність, посилання, нуль, константа і за замовчуванням; en.cppreference.com/w/cpp/language/initialization перераховує всі з прикладами :)
legends2k

Відповіді:


65

Слід усвідомити, що "ініціалізація значення" є новою зі стандартом C ++ 2003 - її немає в оригінальному стандарті 1998 року (я думаю, це може бути єдиною різницею, що є більш ніж уточненням). Дивіться відповідь Кирила В. Лядвінського щодо визначень прямо зі стандарту.

Дивіться цю попередню відповідь про поведінку operator newдля деталей щодо різної поведінки цього типу ініціалізації та коли вони починаються (і коли вони відрізняються від c ++ 98 до C ++ 03):

Основний пункт відповіді:

Іноді пам’ять, повернута новим оператором, буде ініціалізована, а іноді вона не залежатиме від того, тип ви нововведення - це 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;
}

1
Не те, що це має значення int, але m()на третьому рядку значення ініціалізує m. Важливо, якщо ви переходите int m;на B m;. :)
Йоханнес Шауб - ліб

Правильно - Aі Cне використовуються в цьому прикладі (вони переносяться з іншої пов'язаної відповіді). Навіть незважаючи на те, що C ++ 98 та C ++ 03 використовують різні термінології, коли описують, як Aі Cяк будуються, результат є однаковим в обох стандартах. struct BРезультатом є лише інша поведінка.
Майкл Берр

1
що я мав на увазі, що якщо ви зміните C на struct C { C() : m() {}; ~C(); B m; };, то у вас буде m.m0. Але якщо це буде ініціалізація за замовчуванням, mяк ви кажете C ++ 03, m.mце не буде ініціалізовано, як у C ++ 98.
Йоханнес Шауб - ліб

1
Додаткові цікаві коментарі на MSVC обробки цієї функції: stackoverflow.com/questions/3931312 / ...
Brent Bradburn

Яка ініціалізація відбувається, коли ви заявляєте свій тип як локальну змінну, тобто у стеці?
Андре Пуель

89

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

Для того, щоб нуль-ініціалізації об'єкта типу Т означає:
- якщо Т являє собою тип скаляр (3.9), то об'єкт встановлюється в значення 0 (нуль) перетворюється в T;
- якщо T - несоюзний тип класу, кожен нестатичний член даних і кожен суб'єкт базового класу нульово ініціалізується;
- якщо T - тип об'єднання, перший іменований член даних об'єкта ініціалізується нулем;
- якщо T - тип масиву, кожен елемент нульово ініціалізується;
- якщо T - еталонний тип, ініціалізація не проводиться.

Під ініціалізацією за замовчуванням об’єкта типу T означає:
- якщо T - тип класу, який не є POD (пункт 9), конструктор за замовчуванням для T викликається (і ініціалізація неправильно сформована, якщо T не має доступного конструктора за замовчуванням);
- якщо T - тип масиву, кожен елемент ініціалізується за замовчуванням;
- в іншому випадку об'єкт ініціалізується нулем.

Для того, щоб значення ініціалізації об'єкта типу Т означає:
- якщо Т типу класу (пункт 9) з користувачем оголошено конструктором (12.1), то конструктор за замовчуванням для Т називається (і ініціалізація погано формується , якщо Т не має доступного конструктора за замовчуванням);
- якщо T - несоюзний тип класу без оголошеного користувачем конструктора, то кожен нестатичний член даних і компонент базового класу T ініціалізується за значенням;
- якщо T - тип масиву, то кожен елемент ініціалізується за значенням;
- в іншому випадку об'єкт ініціалізується нулем

Програма, яка вимагає ініціалізації за замовчуванням або ініціалізації значення об'єкта еталонного типу, неправильно сформована. Якщо T - тип cv-кваліфікації, для цих визначень нульової ініціалізації, ініціалізації за замовчуванням та ініціалізації значень використовується версія cv-некваліфікована версія T.


18
Це може бути застарілим для C ++ 11. cppreference.com зазначає, що ініціалізація за замовчуванням не містить ініціалізації членів нуля (робить лише ініціалізація значення).
Олексій Шолік

3
@android викликає важливий момент, на який я не бачу відповіді в іншому місці, тому я поставив нове запитання. stackoverflow.com/questions/22233148/…
Адріан Маккарті
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.