Czy członkowie struktury C ++ są domyślnie inicjowani na 0?

200

Mam to struct:

struct Snapshot
{
    double x; 
    int y;
};

Chcę xi ybędę wynosić 0. Czy będą domyślnie wynosić 0 czy czy muszę zrobić:

Snapshot s = {0,0};

Jakie są inne sposoby wyzerowania struktury?

ks1322
źródło
Użyj std :: map <> i zwróć 0, gdy klucz nie istnieje.
Jonny

Odpowiedzi:

263

Nie są zerowe, jeśli nie zainicjujesz struktury.

Snapshot s; // receives no initialization
Snapshot s = {}; // value initializes all members

Drugi spowoduje, że wszyscy członkowie będą zero, pierwszy pozostawi ich na nieokreślonych wartościach. Pamiętaj, że jest rekurencyjny:

struct Parent { Snapshot s; };
Parent p; // receives no initialization
Parent p = {}; // value initializes all members

Drugi spowoduje p.s.{x,y}zero. Nie możesz używać tych zagregowanych list inicjalizacyjnych, jeśli masz w swoim konstruktorze konstruktory. W takim przypadku konieczne będzie dodanie odpowiedniej inicjalizacji do tych konstruktorów

struct Snapshot {
    int x;
    double y;
    Snapshot():x(0),y(0) { }
    // other ctors / functions...
};

Zainicjuje zarówno x, jak i y do 0. Zauważ, że możesz użyć x(), y()do zainicjowania ich bez względu na ich typ: To jest następnie inicjalizacja wartości i zwykle daje prawidłową wartość początkową (0 dla int, 0,0 dla podwójnego, wywoływanie domyślnego konstruktora dla zdefiniowanego przez użytkownika typy, które mają zadeklarowane przez użytkownika konstruktory, ...). Jest to ważne, zwłaszcza jeśli twój struct jest szablonem.

Johannes Schaub - litb
źródło
1
To powoduje wiele ostrzeżeń w moim kompilatorze.
River-Claire Williamson
1
Roger: Spróbuj użyć nazwanej struktury w inicjalizatorze, to właśnie robię i nie otrzymuję żadnych ostrzeżeń w VC 2012: Snapshot s = Snapshot ();
Kit10
@Johannes Schaub - litb Czy będzie Snapshot s = {};działał dla członków spoza POD (do ich zerowania)?
ontherocks
2
C ++ 11 pozwala teraz na inicjalizację ich w definicji struktury lub klasy, na przykład: struct Snapshot {double x {0}; // z nawiasami klamrowymi y = 0; // lub po prostu oldschoolowy styl „przez przypisanie”, który tak naprawdę jest również inicjalizacją};
ikku100
1
Czy „Snapshot s = {};” część standardu?
Stefan
40

Nie, domyślnie nie są to 0. Najprostszym sposobem upewnienia się, że wszystkie wartości lub domyślnie 0 to zdefiniowanie konstruktora

Snapshot() : x(0), y(0) {
}

Zapewnia to, że wszystkie zastosowania migawki będą miały zainicjowane wartości.

JaredPar
źródło
24
Minusem jest to, że struct nie jest już typem POD, ponieważ ma konstruktor. Spowoduje to uszkodzenie niektórych operacji, takich jak zapisanie go do pliku tymczasowego.
finnw
16
@finnw: C ++ 11 naprawia to, chociaż struct nie jest POD, to jest „standardowy układ”.
Ben Voigt,
19

Ogólnie nie. Jednak struktura zadeklarowana jako zakres pliku lub statyczna w funkcji / will / zostanie zainicjowana na 0 (podobnie jak wszystkie inne zmienne tych zakresów):

int x; // 0
int y = 42; // 42
struct { int a, b; } foo; // 0, 0

void foo() {
  struct { int a, b; } bar; // undefined
  static struct { int c, d; } quux; // 0, 0
}
bdonlan
źródło
1
To naprawdę nie jest bezpieczne założenie. nie powinieneś polegać na wartości niczego, czego nie zainicjowałeś
Hasturkun
24
Obiekty statycznego czasu przechowywania są zawsze inicjowane na zero - patrz cytat ze standardu na stackoverflow.com/questions/60653/ ... Czy to dobry styl, to inna sprawa.
bdonlan
12

Z POD możesz także pisać

Snapshot s = {};

Nie powinieneś używać memset w C ++, memset ma tę wadę, że jeśli w strukturze nie ma POD, to go zniszczy.

lub tak:

struct init
{
  template <typename T>
  operator T * ()
  {
    return new T();
  }
};

Snapshot* s = init();
AndersK
źródło
@LightnessRacesinOrbit oh wat?
Ben Sinclair,
@Andy Most Vexing Parse przekształca rzeczy, które wyglądają jak normalne ctors - SomeType foo();jest typowy, choć może się zdarzyć z innymi - w definicje funkcji (w takim przypadku funkcja, fooktóra zwraca SomeType). Przepraszam za nekro, ale jeśli ktokolwiek natknie się na to, pomyślałem, że odpowiem.
Pozew funduszu Moniki
7

W C ++ użyj konstruktorów bez argumentów. W C nie możesz mieć konstruktorów, więc użyj jednego memsetlub - ciekawe rozwiązanie - wyznaczonych inicjatorów:

struct Snapshot s = { .x = 0.0, .y = 0.0 };
Adrian Panasiuk
źródło
Myślę, że to C, a nie C ++. Nie uda się skompilować w niektórych kompilatorach C ++. Wystąpił błąd kompilacji w Cygwin lub MinGW.
jww
3

Uważam, że poprawną odpowiedzią jest to, że ich wartości są niezdefiniowane. Często są one inicjowane na 0 podczas uruchamiania debugowanych wersji kodu. Zwykle nie dzieje się tak podczas uruchamiania wersji.

Eric
źródło
2
W rzeczywistości wersje do debugowania mają już 0w tych miejscach w pamięci. To nie to samo, co inicjalizacja!
Wyścigi lekkości na orbicie
3

Ponieważ jest to POD (zasadniczo struktura C), inicjowanie go w sposób C ma niewielką szkodę:

Snapshot s;
memset(&s, 0, sizeof (s));

lub podobnie

Snapshot *sp = new Snapshot;
memset(sp, 0, sizeof (*sp));

Nie posunąłbym się jednak tak daleko, aby użyć go calloc()w programie C ++.

finnw
źródło
3
To samo dotyczy podwójnego; all-bit-zero niekoniecznie jest 0,0. Możesz jednak sprawdzić, czy masz podwójne IEEE754, w którym to przypadku musi działać.
MSalters
1

Przenieś członków kapsuły do ​​klasy podstawowej, aby skrócić listę inicjalizującą:

struct foo_pod
{
    int x;
    int y;
    int z;
};

struct foo : foo_pod
{
    std::string name;
    foo(std::string name)
        : foo_pod()
        , name(name)
    {
    }
};

int main()
{
    foo f("bar");
    printf("%d %d %d %s\n", f.x, f.y, f.z, f.name.c_str());
}
Bruno Martinez
źródło