Initialisierungsliste

C++ Grundlagen

Die Initialisierungsliste ist ein Werkzeug, das im Konstruktor jeder Klasse eingesetzt werden sollte, die Elemente wie Instanzen anderer Klassen, Zeiger oder integrierter Typen besitzt. In der Initialisierungsliste werden Konstruktoren von Elementen einer Klasse aufgerufen und Variablen oder Zeiger mit einem Anfangswert initialisiert.

class person
{
public:
	person() 
	 : m_name("no name"),
	   m_age(0),
	   m_bestfriend(NULL)
	{}
private:
	std::string m_name;
	unsigned short m_age;
	person * m_bestfriend;
};

Hier wurde eine Klasse person definiert, deren Standardkonstruktor alle Elemente mit einem Startwert initialisiert. Als erstes wird der std::string Konstruktor mit einer konstanten Zeichenkette aufgerufen (Hinweis: Die tatsächliche Abfolge der Aufrufe hängt von anderen Faktoren ab, siehe dazu [1]). Das Alter wird auf 0 festgelegt und der Zeiger auf den besten Freund auf NULL gesetzt. Dieser Konstruktor legt so einen eindeutigen, wenn auch keinen besonders sinnvollen Zustand einer Person fest (Ob die Möglichkeit so eine unsinnige Person zu erstellen ein gutes Design ist, soll hier mal nicht weiter diskutiert werden). Die Definition eines Konstruktors ist nicht zwingend notwendig aber auf jeden Fall zu empfehlen. Wird kein Konstruktor definiert wird, definiert der Compiler einen. Dieser Standardkonstruktor ruft jeweils den Standardkonstruktor alle Klassenelemente auf. In diesem Fall würden hier ein leerer string und die nicht initialisierten Werte m_age und m_bestfriend erzeugt. Nicht initialisiert bedeutet undefiniert. Eine Person die von einem Compiler generierten Konstruktor erzeugt wurde, hat also kein eindeutiges Alter und zeigt auf irgendeinen Speicherbereich, der mit höchster Wahrscheinlichkeit keinen Freund enthält. Der Zugriff auf den nicht initialisierten besten Freund führt zu undefiniertem Verhalten und in aller Regel zum Absturz des Programms.

Dieses schwerwiegende Problem könnte auch ohne Initialisierungsliste beseitigt werden.

class person
{
public:
	person() 
	{
		m_name = "no name";
		m_age = 0;
		m_bestfriend = NULL;
	}
	...
};

Wieso doch eine Initialisierungsliste? In diesem Konstruktor werden alle Elemente durch den Zuweisungsoperator auf ihren Anfangswert gesetzt. Das Ergebnis ist das gleiche. Der Weg über die Initialisierungsliste ist jedoch der kürzere. Betrachten wir die Initialisierung des strings beim Konstruktor ohne Initialisierungsliste. Bevor der Code im Rumpf des Konstruktors ausgeführt wird, werden die Standardkonstruktoren alle Elemente aufgerufen, also string(). Nach der Konstruktion ist m_name leer. Erst im nächsten Schritt wird dem Namen über den = Operator ein Wert zugewiesen. Die Initialisierung benötigt hier also zwei Schritte. Der Konstruktor aus dem ersten Beispiel dagegen ruft string(const char* ptr) auf und erledigt die Initialisierung so in einem Schritt.

Ein anderer Fall, in dem eine Initialisierungsliste zwingend notwendig wird tritt ein, wenn Elemente nicht über einen Standardkonstruktor verfügen (Compiler generieren nur einen Standardkonstruktor, wenn kein Konstruktor definiert wurde). Das folgende Beispiel würde aufgrund eines fehlenden Standardkonstruktors nicht kompilieren.

class person
{
public:
	person(const std::string & name); 
	...
};
class family
{
	person m_mother, m_father;
	std::vector<person> m_children;
};

msvc9 compiler: 
error C2512: 'family' : no appropriate default constructor available

Dieser Fehler kann durch die Definition des folgenden Konstruktors behoben werden.

family() : m_mother("Uschi"), m_father("Klausi")
{}

Links

  1. Reihenfolge von Konstruktoren

Diskussion

Sende ein Kommentar, Frage, Korrekturen, Beschimpfungen...

Name:

Nachricht:


doxapp c++
Zur Übersicht
home