Hinweis:
Siehe dazu auch das Sprachfeature Default-Initialisierung für Member-Variablen.
- Einleitung
- Überblick
- Resümee
- Variablen elementaren Datentyps: Initialisierung mit datentyp-spezifischem Null-Wert
- Variablen elementaren Datentyps: Allgemeine Initialisierung
- Benutzerdefinierte Datentypen: Strukturen
- Benutzerdefinierte Datentypen: Klassen
- Standard STL Container
- Dynamisch allokierte Felder
- Statisch allokierte (bzw. definierte) Felder
- Geschachtelte Strukturen / Brace Elision (Entfernen von Klammern)
- Literaturhinweise
Die Initialisierung mit geschweiften Klammern '{' und '}' ist ab der Version C++–11 eine einheitliche Methode zum Initialisieren von Daten. Sie wird auch als „Uniform Initialization” oder als „Brace Initialization” bezeichnet.
Abbildung 1: C++ und Initialisierung: Relax!
Es lassen sich mit geschweiften Klammern ("Uniform Initialization") alle möglichen Arten einer Variablen-Initialisierung (auch Objekte) mit einer einheitlichen Schreibweise initialisieren. Am besten studiert man die einzelnen Möglichkeiten an Hand der folgenden Systematisierung:
- Variablen elementaren Datentyps: Initialisierung mit datentyp-spezifischem Null-Wert
- Variablen elementaren Datentyps: Allgemeine Initialisierung
- Benutzerdefinierte Datentypen: Strukturen
- Benutzerdefinierte Datentypen: Klassen
- Standard STL Container
- Dynamisch allokierte Felder
- Statisch allokierte (bzw. definierte) Felder
- Geschachtelte Strukturen / Brace Elision (Entfernen von Klammern)
Das Feature der einheitlichen Initialisierung bringt drei Vorteile mit sich:
- Es lassen sich nun manche Konstrukte initialisieren, bei denen das bisher nicht möglich war:
- STL-Containerobjekte
- Arrays, die mit
newallokiert wurden - C-Arrays, die Member-Variablen sind
- Die Einheitlichkeit der neuen Initialisierungssyntax bringt es mit sich, dass man bei konsequentem Einsatz der geschweiften Klammern für die Initialisierung nun leichter zwischen Funktionsaufrufen und Initialisierungen unterscheiden kann:
{ ... } ==> Konstruktor-Aufruf
( ... ) ==> Funktions-/Methoden-Aufruf
- Die einheitliche Initialisierung erlaubt kein „Narrowing”:
double d1 = ival; // Compiles
// double d2{ ival }; // Error: "conversion from 'int' to 'double' requires a narrowing conversion"
Eine genaue Begründung der Fehlermeldung des letzten Beispiels findet man hier.
int n{}; // n equals 0
float f{}; // f equals 0.0
double d{}; // d equals 0.0
unsigned long l{}; // l equals 0
std::size_t i{}; // i equals 0int n{ 1 }; // n equals 1
float f{ 1.5f }; // f equals 1.5
double d{ 2.5 }; // d equals 2.5Bei einer Struktur führt die einheitliche Initialisierung eine direkte Initialisierung ihrer Membervariablen durch:
struct Struct
{
int m_i;
int m_j;
};
void main()
{
struct Struct obj1 {}; // obj1.m_i => 0, obj1.m_j => 0
struct Struct obj2 { 1, 2 }; // obj2.m_i => 1, obj2.m_j => 2
struct Struct obj3 { 3 }; // obj3.m_i => 3, obj3.m_j => 0
}Es ist auch möglich, einer Struktur einen Konstruktor hinzuzufügen. In diesem Fall resultiert die Brace Initialization in einem Aufruf an einen Konstruktor:
struct StructWithCTor
{
int m_i;
int m_j;
StructWithCTor(int i, int j) : m_i{ i }, m_j{ j } {}
};
void main()
{
struct StructWithCTor obj { 5, 6 }; // obj.m_i => 5, obj.m_j => 6
}Bei Klassen führt die Brace Initialization zum Aufruf eines Konstruktors.
class Class
{
private:
int m_a;
int m_b;
public:
Class(int a, int b) : m_a{ a }, m_b{ b } {}
};
void main()
{
Class obj{ 11, 12 }; // obj.m_a => 11, obj.m_b => 12
}std::vector<int> myVector{ 1, 2, 3, 4, 5 };
std::map<std::string, int> myMap
{
{ "Hans", 1958 },
{ "Sepp", 1956 }
};Diese Beispiele stehen zum Teil in Zusammenhang mit der Thematik der Initialisierungs-Liste.
Im Beispiel des std::map-Objekts werden die inneren geschweiften Klammern auf einen
Konstruktoraufruf von std::pair abgebildet (einheitliche Initialisierung).
Die äußeren geschweiften Klammern erzeugen in diesem Beispiel eine Liste des Typs
std::initializer_list<std::pair<std::string, int>>welche dann als Argument für den Aufruf des Sequenzkonstruktors der Klasse std::map dient.
int* pi = new int[5] { 1, 2, 3, 4, 5 };int intArray[] { 1, 2, 3, 4, 5 };struct Inner {
int m_array[2];
};
void main()
{
Inner inner1; // uninitialized
Inner inner2{ }; // m_array[0] => 0 & m_array[1] => 0
Inner inner3{ { 1, 2 } }; // Direct initialization
Inner inner4{ 1, 2 }; // Uses Brace Elision (!) of m_array
}Die Anregungen zu den Beispielen stammen teilweise aus
Bitesize Modern C++: std::initializer_list (abgerufen am 03.12.2022)
und
Brace initialization of user-defined types (abgerufen am 03.12.2022).
