Werden Mitglieder einer C ++ - Struktur standardmäßig auf 0 initialisiert?

199

Ich habe das struct:

struct Snapshot
{
    double x; 
    int y;
};

Ich möchte xund ysoll 0 sein. Werden sie standardmäßig 0 sein oder muss ich Folgendes tun:

Snapshot s = {0,0};

Was sind die anderen Möglichkeiten, um die Struktur auf Null zu setzen?

ks1322
quelle
Verwenden Sie eine std :: map <> und geben Sie 0 zurück, wenn kein Schlüssel vorhanden ist.
Jonny
Beachten Sie, dass die Verwendung unbestimmter Werte undefiniertes Verhalten ist
Shafik Yaghmour

Antworten:

263

Sie sind nicht null, wenn Sie die Struktur nicht initialisieren.

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

Der zweite macht alle Mitglieder auf Null, der erste lässt sie bei nicht spezifizierten Werten. Beachten Sie, dass es rekursiv ist:

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

Der zweite wird p.s.{x,y}Null machen . Sie können diese aggregierten Initialisierungslisten nicht verwenden, wenn Ihre Struktur Konstruktoren enthält. In diesem Fall müssen Sie diesen Konstruktoren eine ordnungsgemäße Initialisierung hinzufügen

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

Initialisiert sowohl x als auch y auf 0. Beachten Sie, dass Sie x(), y()sie unabhängig von ihrem Typ initialisieren können: Dies ist dann die Wertinitialisierung und ergibt normalerweise einen korrekten Anfangswert (0 für int, 0.0 für double, wobei der Standardkonstruktor für benutzerdefiniert aufgerufen wird Typen, die vom Benutzer deklarierte Konstruktoren haben, ...). Dies ist besonders wichtig, wenn Ihre Struktur eine Vorlage ist.

Johannes Schaub - litb
quelle
1
Dies erzeugt viele Warnungen in meinem Compiler.
River-Claire Williamson
1
Roger: Versuche die benannte Struktur im Initialisierer zu verwenden, das ist was ich tue und ich bekomme keine Warnungen in VC 2012: Snapshot s = Snapshot ();
Kit10
@Johannes Schaub - litb Funktioniert Snapshot s = {};für Nicht-POD-Mitglieder (um sie auf Null zu setzen )?
Ontherocks
2
In C ++ 11 können Sie sie jetzt in der Definition der Struktur oder Klasse wie folgt initialisieren: struct Snapshot {double x {0}; // mit geschweiften Klammern int y = 0; // oder einfach nur Old-School-Stil 'durch Zuweisung', was auch wirklich Initialisierung ist};
Ikku100
1
Ist "Snapshot s = {};" Teil des Standards?
Stefan
40

Nein, sie sind standardmäßig nicht 0. Der einfachste Weg, um sicherzustellen, dass alle Werte oder standardmäßig 0 sind, besteht darin, einen Konstruktor zu definieren

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

Dadurch wird sichergestellt, dass alle Verwendungen von Snapshot initialisierte Werte haben.

JaredPar
quelle
24
Der Nachteil ist, dass die Struktur kein POD-Typ mehr ist, da sie einen Konstruktor hat. Dadurch werden einige Vorgänge unterbrochen, z. B. das Schreiben in eine temporäre Datei.
Finnw
16
@finnw: C ++ 11 behebt dies, obwohl die Struktur kein POD ist, sondern "Standardlayout".
Ben Voigt
19

Im Allgemeinen nein. Eine als Dateibereich oder statisch in einer Funktion deklarierte Struktur wird jedoch auf 0 initialisiert (genau wie alle anderen Variablen dieser Bereiche):

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
quelle
1
Das ist wirklich keine sichere Annahme. Sie sollten sich nicht auf den Wert von etwas verlassen, das Sie nicht initialisiert haben
Hasturkun
24
Objekte mit statischer Speicherdauer werden immer auf Null initialisiert - siehe stackoverflow.com/questions/60653/… für ein Zitat aus dem Standard. Ob dies ein guter Stil ist, ist eine andere Frage.
Bdonlan
12

Mit POD können Sie auch schreiben

Snapshot s = {};

Sie sollten memset in C ++ nicht verwenden, memset hat den Nachteil, dass ein Nicht-POD in der Struktur zerstört wird.

oder so:

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

Snapshot* s = init();
AndersK
quelle
@ LightnessRacesinOrbit oh wat?
Ben Sinclair
@Andy Most Vexing Parse verwandelt Dinge, die wie normale Ctors aussehen - dies SomeType foo();ist das typische, obwohl es bei anderen passieren kann - in Funktionsdefinitionen (in diesem Fall eine Funktion foo, die zurückgibt SomeType). Entschuldigung für den Nekro, aber wenn jemand anderes darüber stolpert, würde ich antworten.
Fund Monica Klage
7

Verwenden Sie in C ++ Konstruktoren ohne Argumente. In C können Sie keine Konstruktoren haben, verwenden Sie also entweder memsetoder - die interessante Lösung - bestimmte Initialisierer:

struct Snapshot s = { .x = 0.0, .y = 0.0 };
Adrian Panasiuk
quelle
Ich glaube das ist C, nicht C ++. Unter einigen C ++ - Compilern kann es nicht kompiliert werden. Ich habe den Kompilierungsfehler unter Cygwin oder MinGW erlebt.
JWW
3

Ich glaube, die richtige Antwort ist, dass ihre Werte undefiniert sind. Oft werden sie beim Ausführen von Debug-Versionen des Codes auf 0 initialisiert. Dies ist normalerweise nicht der Fall, wenn Release-Versionen ausgeführt werden.

Eric
quelle
2
Tatsächlich haben die Debug-Versionen gerade schon 0an diesen Stellen im Speicher. Dies ist nicht dasselbe wie Initialisierung!
Leichtigkeitsrennen im Orbit
3

Da dies ein POD (im Wesentlichen eine C-Struktur) ist, schadet es wenig, ihn auf C-Weise zu initialisieren:

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

oder ähnlich

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

Ich würde jedoch nicht so weit gehen, es calloc()in einem C ++ - Programm zu verwenden.

finnw
quelle
3
Gleiches gilt für Doppel; All-Bits-Null ist nicht unbedingt 0.0. Sie können jedoch überprüfen, ob Sie IEEE754-Doppel haben. In diesem Fall muss es funktionieren.
MSalters
1

Verschieben Sie Pod-Mitglieder in eine Basisklasse, um Ihre Initialisierungsliste zu verkürzen:

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
quelle