Wertinitialisierung
Dies ist die Initialisierung, die durchgeführt wird, wenn ein Objekt mit einem leeren Initialisierer konstruiert wird.
Inhalt |
[bearbeiten] Syntax
T () |
(1) | ||||||||
new T () |
(2) | ||||||||
Klasse::Klasse(...) : Mitglied () { ... } |
(3) | ||||||||
T objekt {}; |
(4) | (seit C++11) | |||||||
T {} |
(5) | (seit C++11) | |||||||
new T {} |
(6) | (seit C++11) | |||||||
Klasse::Klasse(...) : Mitglied {} { ... } |
(7) | (seit C++11) | |||||||
[bearbeiten] Erklärung
Wertinitialisierung wird in diesen Situationen durchgeführt
In allen Fällen, wenn das leere geschweifte Klammerpaar {} verwendet wird und T ein Aggregattyp ist, wird stattdessen Aggregatinitialisierung anstelle von Wertinitialisierung durchgeführt.
|
Wenn |
(seit C++11) |
Die Auswirkungen der Wertinitialisierung sind
- Wenn
Tein (möglicherweise cv-qualifizierter) Klassentyp ist
- Wenn die Standardinitialisierung für
Teinen Konstruktor auswählt und der Konstruktor nicht benutzerdeklariert(bis C++11)benutzerbereitgestellt(seit C++11) ist, wird das Objekt zuerst Nullinitialisiert. - In jedem Fall wird das Objekt standardinitialisiert.
- Wenn die Standardinitialisierung für
- Andernfalls, wenn
Tein Arraytyp ist, wird jedes Element des Arrays wertinitialisiert. - Andernfalls wird das Objekt nullinitialisiert.
[bearbeiten] Hinweise
Die Syntax T objekt(); initialisiert kein Objekt; sie deklariert eine Funktion, die keine Argumente annimmt und T zurückgibt. Die Art, ein benanntes Objekt vor C++11 wertzuinitialisieren, war T objekt = T();, was ein temporäres Objekt wertinitialisiert und dann das Objekt durch Kopierinitialisierung initialisiert: Die meisten Compiler optimieren die Kopie in diesem Fall weg.
Referenzen können nicht wertinitialisiert werden.
Wie in Funktionsstil-Cast beschrieben, ist die Syntax T() (1) verboten, wenn T einen Arraytyp benennt, während T{} (5) erlaubt ist.
Alle Standardcontainer (std::vector, std::list, etc.) wertinitialisieren ihre Elemente, wenn sie mit einem einzigen size_type-Argument konstruiert werden oder wenn sie durch einen Aufruf von resize() vergrößert werden, es sei denn, ihr Allocator passt das Verhalten von construct an.
[bearbeiten] Beispiel
#include <cassert> #include <iostream> #include <string> #include <vector> struct T1 { int mem1; std::string mem2; virtual void foo() {} // make sure T1 is not an aggregate }; // implicit default constructor struct T2 { int mem1; std::string mem2; T2(const T2&) {} // user-provided copy constructor }; // no default constructor struct T3 { int mem1; std::string mem2; T3() {} // user-provided default constructor }; std::string s{}; // class => default-initialization, the value is "" int main() { int n{}; // scalar => zero-initialization, the value is 0 assert(n == 0); double f = double(); // scalar => zero-initialization, the value is 0.0 assert(f == 0.0); int* a = new int[10](); // array => value-initialization of each element assert(a[9] == 0); // the value of each element is 0 T1 t1{}; // class with implicit default constructor => assert(t1.mem1 == 0); // t1.mem1 is zero-initialized, the value is 0 assert(t1.mem2 == ""); // t1.mem2 is default-initialized, the value is "" // T2 t2{}; // error: class with no default constructor T3 t3{}; // class with user-provided default constructor => std::cout << t3.mem1; // t3.mem1 is default-initialized to indeterminate value assert(t3.mem2 == ""); // t3.mem2 is default-initialized, the value is "" std::vector<int> v(3); // value-initialization of each element assert(v[2] == 0); // the value of each element is 0 std::cout << '\n'; delete[] a; }
Mögliche Ausgabe
42
[bearbeiten] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 178 | C++98 | es gab keine Wertinitialisierung; ein leerer Initialisierer rief die Standard- Initialisierung auf (obwohl new T() auch Nullinitialisierung durchführt) |
leerer Initialisierer ruft Wertinitialisierung auf |
| CWG 543 | C++98 | die Wertinitialisierung für ein Klassenobjekt ohne benutzerbereitgestellte Konstruktoren war äquivalent zur Wert- Initialisierung jedes Unterobjekts (das keine Null- Initialisierung eines Mitglieds mit einem benutzerbereitgestellten Standardkonstruktor erfordert) |
Nullinitialisiert das gesamte Objekt, ruft dann den Standardkonstruktor |
| CWG 1301 | C++11 | Wertinitialisierung von Unions mit gelöschten Standardkonstruktoren führte zu Nullinitialisierung |
sie sind Standardinitialisiert |
| CWG 1368 | C++98 | jeder benutzerbereitgestellte Konstruktor bewirkte, dass die Nullinitialisierung übersprungen wurde |
nur ein benutzerbereitgestellter Standardkonstruktor überspringt die Nullinitialisierung |
| CWG 1502 | C++11 | die Wertinitialisierung einer Union ohne benutzerbereitgestellten Standardkonstruktor nullinitialisierte nur das Objekt, trotz standardmäßiger Mitgliederinitialisierer |
führt die Standard- Initialisierung nach Nullinitialisierung durch |
| CWG 1507 | C++98 | die Wertinitialisierung für ein Klassenobjekt ohne benutzerbereitgestellte Konstruktoren überprüften nicht die Gültigkeit des Standardkonstruktors, wenn letzterer trivial ist |
die Gültigkeit des trivialen Standardkonstruktor wird überprüft |
| CWG 2820 | C++98 | die Standardinitialisierung nach der Null- Initialisierung erforderte einen nicht-trivialen Konstruktor |
nicht erforderlich. |
| CWG 2859 | C++98 | die Wertinitialisierung für ein Klassenobjekt könnte eine Nullinitialisierung beinhalten, auch wenn die Standard- Initialisierung nicht tatsächlich einen benutzerbereitgestellten Konstruktor auswählt |
es gibt keine Nullinitialisierung durch in diesem Fall |