Standardwerte in einer Struktur initialisieren

73

Wenn ich nur einige ausgewählte Werte einer C ++ - Struktur initialisieren müsste, wäre dies richtig:

struct foo {
    foo() : a(true), b(true) {}
    bool a;
    bool b;
    bool c;
 } bar;

Bin ich davon ausgehen , korrigiere ich mit einem enden würde structElement namens barmit Elementen bar.a = true, bar.b = trueund eine nicht definierte bar.c?

Joe Wilcoxson
quelle
Die Leiste ist nur eine Umbenennung, wenn Sie C ++ verwenden, müssen Sie die Dinge nicht auf diese Weise tun
Aaronon
12
@aaronman nein, barist eine Variable.
Luchian Grigore
5
@ Aarononman Ich denke, Sie verwechseln dies mit typedef struct foo {} bar;.
Urwolf
1
Also, wenn barist die Struktur, was ist foo? Entspricht dies dem Definieren einer fooStruktur und dem separaten Deklarieren einer neuen Variablen barals Typ foo?
Vince
2
Bar ist einfach ein Foo-Objekt. Es ist das gleiche wiestruct foo {//something}; foo bar;
Yan Yi

Antworten:

39

Ja. bar.aund bar.bwerden auf true gesetzt, sind aber bar.cundefiniert. Bestimmte Compiler setzen es jedoch auf false.

Sehen Sie hier ein Live-Beispiel: struct demo

Gemäß C ++ Standard Abschnitt 8.5.12:

Wenn keine Initialisierung durchgeführt wird, hat ein Objekt mit automatischer oder dynamischer Speicherdauer einen unbestimmten Wert

Für primitive integrierte Datentypen ( bool , char, wchar_t, short, int, long, float, double, long double) erhalten nur globale Variablen (alle statischen Speichervariablen) den Standardwert Null, wenn sie nicht explizit initialisiert werden.

Wenn Sie nicht wirklich möchten, dass undefined bar.cmit beginnt, sollten Sie es auch so initialisieren, wie Sie es für bar.aund getan haben bar.b.

taocp
quelle
1
@CaptainObvlious wurde gerade aktualisiert. Tut mir leid, dass ich von anderen Dingen abgelenkt wurde und nicht vom Computer.
Taocp
4
Es ist nicht "undefiniert", es ist nicht initialisiert , was bedeutet, dass es einen unbestimmten Wert hat .
Jonathan Wakely
Ich denke, OP wollte sagen, dass der Wert undefiniert ist, nicht das Mitglied.
Srujzs
236

Sie müssen nicht einmal einen Konstruktor definieren

struct foo {
    bool a = true;
    bool b = true;
    bool c;
 } bar;

Zur Verdeutlichung: Diese werden als Klammer- oder Gleichheitsinitialisierer bezeichnet (da Sie anstelle des Gleichheitszeichens auch die Klammerinitialisierung verwenden können). Dies gilt nicht nur für Aggregate: Sie können dies in normalen Klassendefinitionen verwenden. Dies wurde in C ++ 11 hinzugefügt.

Erik van Velzen
quelle
116
Downvoters: Bitte machen Sie sich mit den C ++ 11-Updates des Standards vertraut, bevor Sie die Leute darüber belehren, was legal ist oder nicht. Es kompiliert eigentlich ganz gut. Dies ist C ++ 11 und C ++ 11 ist C ++, bis eine neue Version übernommen wird.
Ben Voigt
10
@ BenVoigt Ah, C ++ 11. Mein Fehler. Das tut mir leid.
Jamesdlin
5
@jamesdlin: Seit dem 21. August 2011 c++bedeutet das Tag C ++ 11. Leute können gerne C ++ 98 oder C ++ 03 sagen, wenn sie eine alte Version diskutieren wollen. Und irgendwann im nächsten Jahr wird sich das nackte c++Tag wieder ändern und C ++ 14 bedeuten.
Ben Voigt
2
@ BenVoigt Ja, ich weiß. Mir war gerade völlig klar geworden, dass dies eine der Funktionen war, die in C ++ 11 hinzugefügt wurden.
Jamesdlin
6
Es ist erwähnenswert, dass dies den Typ sofort zu einem Nicht-POD (verifiziert über std::is_pod<T>::value) macht und in diesem Sinne dem Schreiben eines nicht standardmäßigen Konstruktors entspricht, der dieselben Werte in einer Initialisiererliste festlegt.
underscore_d
8

Sie können dies mit einem Konstruktor wie dem folgenden tun:

struct Date
{
int day;
int month;
int year;

Date()
{
    day=0;
    month=0;
    year=0;
}
};

oder so:

struct Date
{
int day;
int month;
int year;

Date():day(0),
       month(0),
       year(0){}
};

In Ihrem Fall ist bar.c undefiniert und sein Wert hängt vom Compiler ab (während a und b auf true gesetzt wurden).

Nicola
quelle
13
Es gibt keinen Grund, die erste Form zu bevorzugen. Sie sollten Initialisierungslisten verwenden.
Jamesdlin
@jamesdlin stimmte in 99,9% der Fälle zu, in denen der 2. aus unzähligen Gründen sehr vorzuziehen ist. jedoch - nur um den Anwalt des Teufels zu spielen! - Wenn intdie Mitglieder anstelle von s benutzerdefinierte Klassen wären , die die Definition von trivial erfüllen müssten (z. B. kein nicht standardmäßiger Konstruktor), wäre dies ein Grund, im Body zuzuweisen, anstatt in der Init-Liste zu konstruieren. Die Anzahl der Szenarien, in denen dies nützlich ist, ist jedoch vermutlich eine winzige Minderheit. Daher sollten Init-Listen definitiv die Standardempfehlung sein - mit den seltenen Ausnahmen, die im Gegensatz zu hier sorgfältig qualifiziert und gerechtfertigt sind.
underscore_d
1
@underscore_d Nein, das wäre kein solcher Grund. Sie können Initialisiererlisten in allen Fällen verwenden, außer wenn Mitgliedsvariablen voneinander abhängig sind, und dies ist eine Verletzung von 3NF ;-)
user207421
@EJP Es ist sehr viel kann ein Grund sein; Ich habe es mehrmals gebraucht. Ich denke, Sie konzentrieren sich auf die Initialisierung der Eltern, aber ich spreche über ihre Mitglieder. Für Mitgliedsobjekte, deren defaultCtors unangemessen sind und deren Standardlayout Nichtkonstruktoren ausschließt default, muss die Initialisierung auf eine andere Weise durchgeführt werden, sei es operator=oder eine Init-Funktion oder was auch immer. Es ist sinnvoll, diese "Initialisierung" im Konstruktor des Elternteils durchzuführen, dh in seinem Körper zuzuweisen. operator=Dies entspricht der In-Body-Zuordnung von Grundelementen wie in der Post. Überdenken oder tangential vielleicht, aber wahr ;-)
underscore_d
1
@GabrielStaples Wenn Sie einzelne Elemente eines Arrays initialisieren, müssen Sie dies in einem Konstruktorkörper tun. Offensichtlich gibt es einige Dinge, die in einem Konstruktorkörper erledigt werden müssen . In meinem früheren Kommentar ging es speziell um die spezifischen Beispiele in dieser Antwort.
Jamesdlin
2

Eine explizite Standardinitialisierung kann helfen:

struct foo {
    bool a {};
    bool b {};
    bool c {};
 } bar;

Verhalten bool a {}ist das gleiche wie bool b = bool();und zurück false.

Anamnian
quelle