Kopierkonstruktor

Kopierkonstruktor

Ein Kopierkonstruktor, oft Copy-Konstruktor genannt, ist in der Objektorientierten Programmierung ein spezieller Konstruktor, der eine Referenz auf ein Objekt desselben Typs als Parameter entgegennimmt und die Aufgabe hat, eine Kopie des Objektes zu erstellen.

Inhaltsverzeichnis

Beispiel

Als Beispiel dient eine Klasse, die eine Zeichenkette oder eine Klasse selben Typs über ihren Konstruktor verarbeitet. Das folgende Beispiel in C++ zeigt zum Vergleich einen gewöhnlichen Konstruktor und einen Kopierkonstruktor:

class MitCopyKonstruktor
{
private:
  char *cString;
 
public:
  // gewöhnlicher Konstruktor
  MitCopyKonstruktor(const char* value) 
  {
    cString = new char[strlen(value) + 1]; // Speicher der richtigen Länge reservieren
    strcpy(cString, value);  // Den String aus value in den reservierten Speicher kopieren
  }
 
  // Kopierkonstruktor:
  // hat in C++ immer die Signatur "Klassenname(const Klassenname&)"
  MitCopyKonstruktor(const MitCopyKonstruktor& rhs) // Üblicherweise rhs: "Right Hand Side"
  {
    cString = new char[strlen(rhs.cString) + 1];
    strcpy(cString, rhs.cString);
  }
};

Aufruf

Der Kopierkonstruktor wird bei der Initialisierung eines Objektes mittels eines anderen Objekts desselben Typs aufgerufen. In C++ wird dieses andere Objekt als einziger Parameter dem Konstruktor übergeben. Es erfolgt in der Deklaration des Objektes die Zuweisung des anderen Objektes oder das Objekt wird als Wertparameter an eine Funktion oder Methode übergeben.

Beispiel in C++ (Fortsetzung):

int main()
{
MitCopyKonstruktor mitCC("Dulz");    // Erstellt eine Zeichenkette 
MitCopyKonstruktor mitCC2 = mitCC;  // Kopierkonstruktor, Zuweisungssyntax
MitCopyKonstruktor mitCC3(mitCC);    // Kopierkonstruktor, Aufrufsyntax
}

Verwendung

Einige Programmiersprachen, wie beispielsweise C++, stellen einen vordefinierten Kopierkonstruktor zur Verfügung, der einfach die Elementvariablen des zu kopierenden Objektes in die des zu initialisierenden Objektes kopiert. (In anderen Programmiersprachen, z. B. Java, muss der Kopierkonstruktor explizit programmiert werden.) Manchmal ist das allerdings nicht ausreichend. Sind unter den Elementvariablen nämlich Handles auf Ressourcen und gibt das bereits existente Objekt die Ressourcen frei, so ist das Handle in dem per Standard-Kopierkonstruktor erstellten Objekt ungültig und seine Verwendung kann dann zu Programmabstürzen führen.

Im Beispiel enthält jede Instanz von Zeichenkette ihren eigenen Speicher, der beim Aufruf des Kopierkonstruktors reserviert wird. Wenn jede Kopie eines Objektes exklusiven Zugriff auf ihre Ressourcen hat, d. h. sie nicht mit anderen Objekten teilen muss, spricht man von einer tiefen Kopie (engl. deep copy). Andernfalls spricht man von einer flachen Kopie (engl. shallow copy). Eine flache Kopie produziert der Compiler mit dem vordefinierten Kopierkonstruktor automatisch. Ist in der Klasse Zeichenkette kein Kopierkonstruktor definiert, der eine tiefe Kopie erstellt, würden nach einer Kopie zwei Objekte einen Zeiger auf denselben Speicherblock haben, da die Adresse einfach kopiert werden würde. Ein Objekt weiß dann aber nicht, ob das andere bereits delete auf dem Speicherblock aufgerufen hat. Sowohl ein Zugriff auf den Speicher als auch ein erneutes delete würden dann zu einem Absturz des Programmes führen. Folgendes Beispiel illustriert dies.

Beispiel in C++ (gekürzt):

class ZeichenketteF 
{
public:
  ZeichenketteF() : m_memory(NULL) {} // Standardkonstruktor
  ZeichenketteF(const char* value)    // Konstruktor
  {
    m_memory = new char[strlen(value) + 1]; // Speicher der richtigen Länge reservieren
    strcpy(m_memory, value);                // Den String aus value in den reservierten Speicher kopieren
  }
  // die Klasse ZeichenketteF übernimmt den Standard-Kopierkonstruktor
 
private:
  char *m_memory;
};
 
void scheitere()
{ 
  ZeichenketteF name("Wolfgang");
 
  // anonymer Block für neuen Gültigkeitsbereich:
  {
    ZeichenketteF kopie(name); // Nun wird eine so genannte [[flache Kopie]] erstellt.
    // Sowohl name.m_memory als auch kopie.m_memory zeigen nun auf denselben Speicher!
  } // automatischer Destruktoraufruf für kopie, gibt Speicher, auf den m_memory zeigt, frei
    // das Objekt name verweist weiter auf - einen nun freigegebenen - Speicherbereich
 
} // automatischer Destruktoraufruf für name. 
  // Der Versuch, denselben Speicherblock erneut freizugeben, führt (vielleicht nur) zu einem Absturz

Kosten tiefer Kopien

Wie am Beispiel unter Aufruf sichtbar, finden tiefe Kopien statt, daraus folgt eine gewisse Last. Zur Vermeidung unnötiger Last empfehlen sich zwei Varianten der oben dargestellten Kopier-Strategie.

  • Ressourcen mittels Referenzzählung in verschiedenen Instanzen gemeinsam zu nutzen; viele Implementierungen der Klasse String machen hiervon Gebrauch.
  • konstante Referenzen als Parameter in Funktionen und Methoden zu übernehmen, in all den Fällen, in denen auf Parameter nur lesend zugegriffen wird.

Der Kopierkonstruktor selbst zeigt in seinem Prototyp wie man unnötige tiefe Kopien von Objekten vermeidet, auf die man nur lesend zugreifen muss: Er übernimmt eine konstante Referenz, denn sonst müsste er ja (implizit) aufgerufen werden, bevor er aufgerufen wird! Die Signatur "Klassenname(const Klassenname&)" ist auch deshalb typisch.

Siehe auch


Wikimedia Foundation.

Игры ⚽ Нужно решить контрольную?

Schlagen Sie auch in anderen Wörterbüchern nach:

  • Copy-Konstruktor — Ein Kopierkonstruktor (auch Copy Konstruktor) ist in der Informatik ein spezieller Konstruktor, der eine Referenz auf ein Objekt desselben Typs als Parameter entgegennimmt und die Aufgabe hat, eine Kopie des Objektes zu erstellen.… …   Deutsch Wikipedia

  • Kopiekonstruktor — Ein Kopierkonstruktor (auch Copy Konstruktor) ist in der Informatik ein spezieller Konstruktor, der eine Referenz auf ein Objekt desselben Typs als Parameter entgegennimmt und die Aufgabe hat, eine Kopie des Objektes zu erstellen.… …   Deutsch Wikipedia

  • Dreierregel — Die Dreierregel, auch bekannt als Die Große Drei oder Regel der Großen Drei bezeichnet in C++ eine Daumenregel, die besagt, dass, wenn eine Klasse oder ein Struct eines der folgenden drei definiert, meistens auch die anderen beiden definiert… …   Deutsch Wikipedia

  • Constructor — Als Konstruktoren und Destruktoren werden in der Programmierung spezielle Prozeduren bezeichnet, die beim Erzeugen und Zerstören von Objekten oder Variablen aufgerufen werden. Konstruktoren bringen die Objekte in einen definierten Anfangszustand …   Deutsch Wikipedia

  • Destruktor — Als Konstruktoren und Destruktoren werden in der Programmierung spezielle Prozeduren bezeichnet, die beim Erzeugen und Zerstören von Objekten oder Variablen aufgerufen werden. Konstruktoren bringen die Objekte in einen definierten Anfangszustand …   Deutsch Wikipedia

  • Dreierregel (C++) — Die Dreierregel, auch bekannt als Die Große Drei oder Regel der Großen Drei bezeichnet in C++ eine Daumenregel, die besagt, dass, wenn eine Klasse eines der folgenden drei definiert, meistens auch die anderen beiden definiert werden sollten[1]:… …   Deutsch Wikipedia

  • Einzelstück (Entwurfsmuster) — Das Singleton (auch Einzelstück genannt) ist ein in der Softwareentwicklung eingesetztes Entwurfsmuster und gehört zur Kategorie der Erzeugungsmuster (engl. Creational Patterns). Es verhindert, dass von einer Klasse mehr als ein Objekt erzeugt… …   Deutsch Wikipedia

  • Konstruktor — Als Konstruktoren und Destruktoren werden in der Programmierung spezielle Prozeduren bezeichnet, die beim Erzeugen und Zerstören von Objekten oder Variablen aufgerufen werden. Konstruktoren bringen die Objekte in einen definierten Anfangszustand …   Deutsch Wikipedia

  • Singleton Pattern — Das Singleton (auch Einzelstück genannt) ist ein in der Softwareentwicklung eingesetztes Entwurfsmuster und gehört zur Kategorie der Erzeugungsmuster (engl. Creational Patterns). Es verhindert, dass von einer Klasse mehr als ein Objekt erzeugt… …   Deutsch Wikipedia

  • Is-a — Vererbung dargestellt mittels UML. Die abgeleitete Klasse hat die Attribute x und y und verfügt über die Methoden a und b (im UML Sprachgebrauch Operationen a und b). Die Vererbung (engl. Inheritance) ist eines der grundlegenden Konzepte der… …   Deutsch Wikipedia

Share the article and excerpts

Direct link
Do a right-click on the link above
and select “Copy Link”