Ich bin sehr verwirrt über Wert- & Standard- & Null-Initialisierung. und vor allem, wenn sie sich für die verschiedenen Standards C ++ 03 und C ++ 11 (und C ++ 14 ) einsetzen.
Ich zitiere und versuche, eine wirklich gute Antwort Value- / Default- / Zero-Init C ++ 98 und C ++ 03 hier zu erweitern, um sie allgemeiner zu gestalten, da es vielen Benutzern helfen würde, wenn jemand beim Ausfüllen helfen könnte Benötigten Sie Lücken, um einen guten Überblick darüber zu erhalten, was wann passiert?
Der vollständige Einblick anhand von Beispielen auf den Punkt gebracht:
Manchmal wird der vom neuen Operator zurückgegebene Speicher initialisiert, und manchmal hängt es nicht davon ab, ob der Typ, den Sie neu erstellen, ein ist POD (einfache alte Daten) ist oder ob es sich um eine Klasse handelt, die POD-Mitglieder enthält und eine verwendet Vom Compiler generierter Standardkonstruktor.
- In C ++ 1998 gibt es zwei Arten der Initialisierung: Null- und Standardinitialisierung
- In C ++ 2003 wurde eine dritte Art der Initialisierung, die Wertinitialisierung, hinzugefügt.
- In C ++ 2011 / C ++ 2014 nur list-Initialisierung wurde hinzugefügt und die Regeln für die wert- / Default- / Null-Initialisierung ein wenig verändert.
Annehmen:
struct A { int m; };
struct B { ~B(); int m; };
struct C { C() : m(){}; ~C(); int m; };
struct D { D(){}; int m; };
struct E { E() = default; int m;}; /** only possible in c++11/14 */
struct F {F(); int m;}; F::F() = default; /** only possible in c++11/14 */
In einem C ++ 98-Compiler sollte Folgendes auftreten :
new A
- unbestimmter Wert (A
ist POD)new A()
- Nullinitialisierungnew B
- Standardkonstrukt (B::m
ist nicht initialisiert,B
ist kein POD)new B()
- Standardkonstrukt (B::m
ist nicht initialisiert)new C
- Standardkonstrukt (C::m
ist nullinitialisiert,C
kein POD)new C()
- Standardkonstrukt (C::m
ist nullinitialisiert)new D
- Standardkonstrukt (D::m
ist nicht initialisiert,D
ist kein POD)new D()
- Standardkonstrukt? (D::m
ist nicht initialisiert)
In einem C ++ 03-konformen Compiler sollten die Dinge so funktionieren:
new A
- unbestimmter Wert (A
ist POD)new A()
- WertinitialisierungA
, dh Nullinitialisierung, da es sich um einen POD handelt.new B
- Standardinitialisierung (lässtB::m
nicht initialisiert,B
ist kein POD)new B()
- Wert initialisiertB
dem alle Felder mit Null initialisiert werden, da der Standard-ctor vom Compiler generiert wird und nicht benutzerdefiniert.new C
- default-initializesC
, der den Standard-ctor aufruft. (C::m
ist nullinitialisiert,C
kein POD)new C()
- value-initializesC
, der den Standard-ctor aufruft. (C::m
ist nullinitialisiert)new D
- Standardkonstrukt (D::m
ist nicht initialisiert,D
ist kein POD)new D()
- Wert initialisiert D? , der den Standard-Ctor aufruft (D::m
ist nicht initialisiert)
Kursive Werte und? Sind Unsicherheiten, bitte helfen Sie dies zu korrigieren :-)
In einem C ++ 11-konformen Compiler sollten die Dinge so funktionieren:
??? (Bitte helfen Sie, wenn ich hier anfange, wird es sowieso schief gehen)
In einem C ++ 14-konformen Compiler sollten die Dinge so funktionieren: ??? (Bitte helfen Sie, wenn ich hier anfange, wird es trotzdem schief gehen) (Entwurf basierend auf Antwort)
new A
- Standard-InitialisierungenA
, Compiler-Gen. ctor, (verlässtA::m
nicht initialisiert) (A
ist POD)new A()
- Wertinitialisierung, dh NullinitialisierungA
seit 2. Punkt in [dcl.init] / 8new B
- Standard-InitialisierungenB
, Compiler-Gen. ctor, (verlässtB::m
nicht initialisiert) (B
ist kein POD)new B()
- value-initializes, beiB
dem alle Felder mit Null initialisiert werden, da der Standard-ctor vom Compiler generiert wird und nicht benutzerdefiniert.new C
- default-initializesC
, der den Standard-ctor aufruft. (C::m
ist nullinitialisiert,C
kein POD)new C()
- value-initializesC
, der den Standard-ctor aufruft. (C::m
ist nullinitialisiert)new D
- StandardinitialisierungenD
(D::m
ist nicht initialisiert,D
ist kein POD)new D()
- value-initializesD
, der den Standard-ctor aufruft (D::m
nicht initialisiert)new E
- default-initializesE
, wodurch der Comp aufgerufen wird. gen. ctor. (E::m
ist nicht initialisiert, E ist kein POD)new E()
- WertinitialisierungenE
, dieE
seit 2 Punkten in [dcl.init] / 8 ) mit Null initialisiert werden )new F
- default-initializesF
, wodurch der Comp aufgerufen wird. gen. ctor. (F::m
ist nicht initialisiert,F
ist kein POD)new F()
- value-initializesF
, die seit dem 1. Punkt in [dcl.init] / 8 standardmäßig initialisiert werden ( ctor-Funktion wird vom Benutzer bereitgestellt, wenn sie vom Benutzer deklariert und bei ihrer ersten Deklaration nicht explizit standardmäßig standardisiert oder gelöscht wird. Link )F
F
struct D { D() {}; int m; };
kann es sich lohnen, es in Ihre Liste aufzunehmen.Antworten:
C ++ 14 spezifiziert die Initialisierung von Objekten, die mit
new
in [expr.new] / 17 erstellt wurden ([expr.new] / 15 in C ++ 11, und die Notiz war damals keine Notiz, sondern normativer Text):Die Standardinitialisierung ist in [dcl.init] / 7 definiert (/ 6 in C ++ 11, und der Wortlaut selbst hat den gleichen Effekt):
So
new A
bewirkt lediglich, dass derA
Standardkonstruktor s aufgerufen wird, der nicht initialisiert wirdm
. Unbestimmter Wert. Sollte das gleiche sein fürnew B
.new A()
wird gemäß [dcl.init] / 11 (/ 10 in C ++ 11) interpretiert:Und nun betrachten Sie [dcl.init] / 8 (/ 7 in C ++ 11 †):
Daher
new A()
wird Null initialisiertm
. Und das sollte fürA
und gleichwertig seinB
.new C
undnew C()
initialisiert das Objekt standardmäßig erneut, da der erste Aufzählungspunkt aus dem letzten Anführungszeichen gilt (C verfügt über einen vom Benutzer bereitgestellten Standardkonstruktor!).m
In beiden Fällen wird jetzt eindeutig im Konstruktor initialisiert.† Nun, dieser Absatz hat in C ++ 11 einen etwas anderen Wortlaut, was das Ergebnis nicht ändert:
quelle
struct A { int m; }; struct C { C() : m(){}; int m; };
unterschiedliche Ergebnisse erzeugt werden und warum m in A überhaupt initialisiert wird. Ich habe einen speziellen Thread für das Experiment geöffnet, das ich durchgeführt habe, und ich werde mich über Ihre Beiträge dort freuen, um das Problem zu klären. Vielen Dank stackoverflow.com/questions/45290121/…Die folgende Antwort erweitert die Antwort https://stackoverflow.com/a/620402/977038 die als Referenz für C ++ 98 und C ++ 03 dienen würde
Die Antwort zitieren
C ++ 11 (In Bezug auf n3242)
Initialisierer
8.5 Initialisierer [dcl.init] Gibt an, daß eine Variable oder nicht POD POD kann entweder als initialisiert wird Klammer-oder-gleich-Initialisierer der entweder sein kann verspannt-init-Liste oder Initialisierer-Klausel aggregately bezeichnet als Klammer-or-gleichschenkligen Initialisierer oder using (Ausdrucksliste) . Vor C ++ 11 wurde nur (Ausdrucksliste) oder Initialisierer-Klausel unterstützt, obwohl die Initialisierer-Klausel eingeschränkter war als in C ++ 11. In C ++ 11 unterstützt die initializer-Klausel jetzt die Klammer-Init-Liste, abgesehen vom Zuweisungsausdruckwie in C ++ 03. Die folgende Grammatik fasst die neue unterstützte Klausel zusammen, bei der der fett gedruckte Teil im C ++ 11-Standard neu hinzugefügt wurde.
Initialisierer:
Klammer-oder-gleich-Initialisierer
(Ausdrucksliste)
Klammer-oder-gleich-Initialisierer:
= Initialisierer-Klausel Klammer-
Init-Liste
Initialisierer-Klausel:
Zuweisungsausdruck Klammer
-Init-Liste
Initialisierer-Liste:
Initialisierer-Klausel ... opt
Initialisierer-Liste, Initialisierer-Klausel ... opt **
Klammer-Init-Liste:
{Initialisierer-Liste, opt}
{}
Initialisierung
Wie C ++ 03 unterstützt C ++ 11 weiterhin drei Formen der Initialisierung
Hinweis
Initialisierungstyp: 8.5.5 [dcl.init] _zero-initialize_
Wird in den folgenden Fällen durchgeführt
2. Initialisierungstyp: 8.5.6 [dcl.init] _default-initialize_
Wird in den folgenden Fällen durchgeführt
3. Initialisierungstyp: 8.5.7 [dcl.init] _value-initialize_
Also um es zusammenzufassen
quelle
Ich kann bestätigen, dass in C ++ 11 alles, was in der Frage unter C ++ 14 erwähnt wird, korrekt ist, zumindest gemäß den Compiler-Implementierungen.
Um dies zu überprüfen, habe ich meiner Testsuite den folgenden Code hinzugefügt . Ich habe mit
-std=c++11 -O3
in GCC 7.4.0, GCC 5.4.0, Clang 10.0.1 und VS 2017 getestet und alle folgenden Tests sind bestanden.Die Orte, an denen
UB!
erwähnt wird, sind undefiniertes Verhalten, und das tatsächliche Verhalten hängt wahrscheinlich von vielen Faktoren ab (a.m
kann 42, 0 oder einem anderen Müll entsprechen). Die Orte, an denen~UB
erwähnt wird, sind auch theoretisch undefiniertes Verhalten, aber in der Praxis ist es aufgrund der Verwendung eines neuen Praktikums sehr unwahrscheinlicha->m
, dass es irgendetwas anderem als 42 entspricht.quelle