Co oznaczają następujące frazy w C ++: inicjalizacja zera, domyślna i wartość?

190

Co oznaczają następujące frazy w C ++:

  • inicjalizacja zerowa,

  • domyślna inicjalizacja oraz

  • inicjalizacja wartości

Co powinien wiedzieć o nich programista C ++?

Rachunek
źródło
1
Jest to powiązane z (ale nie identyczne z) stackoverflow.com/questions/620137/...
Steve Jessop,
20
Jest więcej! Pełna lista inicjalizacji: wartość, bezpośrednie, kopiowanie, lista (nowe wprowadzenie C ++ 11), agregacja, referencja, zero, stała i domyślna; en.cppreference.com/w/cpp/language/initialization wyświetla wszystkie z przykładami :)
legends2k

Odpowiedzi:

65

Należy zdać sobie sprawę z tego, że inicjalizacja wartości jest nowa w standardzie C ++ 2003 - nie istnieje w oryginalnym standardzie z 1998 roku (myślę, że może to być jedyna różnica, która jest czymś więcej niż wyjaśnieniem). Zobacz odpowiedź Kirilla V. Lyadvinsky'ego na definicje prosto ze standardu.

Zobacz poprzednią odpowiedź na temat zachowania, operator newaby uzyskać szczegółowe informacje na temat różnych zachowań tego typu inicjowania i kiedy się uruchamiają (i kiedy różnią się od c ++ 98 do C ++ 03):

Głównym punktem odpowiedzi jest:

Czasami pamięć zwrócona przez nowego operatora zostanie zainicjowana, a czasem nie będzie zależeć od tego, czy nowy typ jest POD, czy też jest klasą zawierającą elementy POD i używa domyślnego konstruktora generowanego przez kompilator .

  • W C ++ 1998 istnieją 2 rodzaje inicjalizacji: zero i domyślna
  • W C ++ 2003 dodano trzeci typ inicjalizacji, inicjalizację wartości.

Mówiąc najprościej, jest to dość skomplikowane i kiedy różne metody są subtelne.

Należy z pewnością pamiętać, że MSVC przestrzega zasad C ++ 98, nawet w VS 2008 (VC 9 lub cl.exe wersja 15.x).

Poniższy fragment pokazuje, że MSVC i Digital Mars przestrzegają zasad C ++ 98, podczas gdy GCC 3.4.5 i Comeau przestrzegają zasad 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;
}
Michael Burr
źródło
1
Nie ma to znaczenia int, ale m()w trzecim wierszu wartość inicjuje m. Ważne, jeśli zmienisz int m;na B m;. :)
Johannes Schaub - litb
Racja - Ai Cnie są używane w tym przykładzie (zostały przeniesione z innej połączonej odpowiedzi). Mimo że C ++ 98 i C ++ 03 używają innej terminologii przy opisywaniu sposobu Ai Cbudowy, wynik jest taki sam w obu standardach. struct BPowoduje tylko inne zachowanie.
Michael Burr
1
Chodzi mi o to, że jeśli zmienisz C na struct C { C() : m() {}; ~C(); B m; };, to będziesz mieć m.m0. Ale jeśli byłaby to inicjalizacja domyślna mtak jak mówisz C ++ 03, to m.mnie byłaby inicjowana jak w C ++ 98.
Johannes Schaub - litb
1
Dodatkowe interesujące komentarze na temat obsługi tej funkcji przez MSVC: stackoverflow.com/questions/3931312/…
Brent Bradburn
Która inicjalizacja ma miejsce, gdy zadeklarujesz swój typ jako zmienną lokalną, tj. Na stosie?
André Puel
89

C ++ 03 Standard 8.5 / 5:

Do zera inicjalizacji przedmiot oznacza typ T:
- jeśli T typu skalarny (3,9), których celem jest ustawiana na wartość 0 (zerowy) w przeliczeniu na T;
- jeżeli T jest niekluczowym typem klasy, każdy niestatyczny element danych i każdy podklucz klasy podstawowej jest inicjowany na zero;
- jeśli T jest typem unii, pierwszy nazwany element danych obiektu jest inicjowany na zero;
- jeśli T jest typem tablicy, każdy element jest inicjowany zerem;
- jeżeli T jest typem odniesienia, inicjalizacja nie jest przeprowadzana.

Do domyślnych zainicjować obiekt środków typ T:
- jeśli T jest non-POD typ zajęć (pkt 9), konstruktor domyślny dla T nazywa (i inicjalizacji jest źle sformułowane jeśli T ma dostępnego domyślnego konstruktora);
- jeśli T jest typem tablicy, każdy element jest inicjowany domyślnie;
- w przeciwnym razie obiekt jest inicjowany na zero.

Do wartości inicjalizacji przedmiot oznacza typ T:
- jeśli T typu klasy (punkt 9) z konstruktora dla deklarowanej (12,1), a następnie konstruktor domyślną T nazywa (i inicjalizacji źle tworzy jeśli T nie ma dostępnego domyślnego konstruktora);
- jeżeli T jest niezwiązkowym typem klasy bez konstruktora zadeklarowanego przez użytkownika, to każdy niestatyczny element danych i składnik klasy podstawowej T jest inicjalizowany pod względem wartości;
- jeśli T jest typem tablicy, to każdy element jest inicjowany wartością;
- w przeciwnym razie obiekt jest inicjowany na zero

Program, który wymaga inicjalizacji domyślnej lub inicjalizacji wartości encji typu odniesienia jest źle sformułowany. Jeśli T jest typem kwalifikowanym do cv, w tych definicjach zerowej inicjalizacji, domyślnej inicjalizacji i inicjalizacji wartości używana jest wersja T niekwalifikowana do CV.

Kirill V. Lyadvinsky
źródło
18
To może być nieaktualne dla C ++ 11. cppreference.com stwierdza, że ​​domyślna inicjalizacja nie inicjuje elementów zerowych (robi to tylko inicjalizacja wartości).
Alexei Sholik
3
@android podnosi ważną kwestię, na którą nie widzę odpowiedzi gdzie indziej, więc zadałem nowe pytanie. stackoverflow.com/questions/22233148/…
Adrian McCarthy