Copy constructor

from Wikipedia, the free encyclopedia

A copy constructor , often called a copy constructor , is a special constructor in object-oriented programming which accepts a reference to an object of the same type as a parameter and has the task of creating a copy of the object.

example

A class that processes a character string or a class of the same type via its constructor serves as an example. The following example in C ++ shows a common constructor and a copy constructor for comparison:

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);
  }
};

call

The copy constructor is called when an object is initialized using another object of the same type. In C ++, this other object is passed as the only parameter to the constructor. The other object is assigned in the declaration of the object or the object is transferred to a function or method as a value parameter .

Example in C ++ (continued):

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

use

Some programming languages, such as C ++ , provide a predefined copy constructor that simply copies the element variables of the object to be copied into those of the object to be initialized. (In other programming languages, e.g. Java , the copy constructor must be programmed explicitly.) However, this can lead to problems. If there are handles on resources under the element variables and the existing object releases the resources, the handle in the object created using the standard copy constructor is invalid and its use can then lead to program crashes. Pointers to memory areas are also copied so that the copy of the original object now has pointers to memory areas that are already in use. If these memory areas are now changed, e.g. B. by changing the origin or the copied object, this affects all objects that use pointers to the same memory area.

In the example, each instance of the character string contains its own memory, which is reserved when the copy constructor is called. When each copy of an object has exclusive access to its resources, i. h., they do not share with other objects must, it is called a deep copy (Engl. deepCopy ). Otherwise, one speaks of a flat copy (engl. Shallow copy ). The compiler automatically produces a shallow copy with the predefined copy constructor. If no copy constructor is defined in the String class that creates a deep copy, two objects would have a pointer to the same memory block after a copy, since the address would simply be copied. One object then does not know whether the other has already called delete on the memory block. Both an access to the memory and a renewed delete would then lead to a crash of the program. The following example illustrates this.

Example in C ++ (shortened):

class ZeichenketteF 
{
public:
    /*
    * Konstruktor mit Parameter.
    * In der Initialisierungsliste wird der Zeiger m_memory so 
    * initialisiert, dass er auf den neu reservierten Speicher auf dem 
    * Heap zeigt.
    */
    explicit ZeichenketteF(const char* value) :
        m_memory(new char[strlen(value) + 1]) 
    {
        // Kopiert den String aus value in den reservierten Speicher
        strcpy(m_memory, value);
    }

    /*
     * Destruktor.
     */
    ~ZeichenketteF()
    {
        // Gibt den im Konstruktor reservierten Speicher wieder frei
        delete m_memory;
    }

    /*
     * Kopierkonstruktor.
     * In der Initialisierungsliste wird der Zeiger z.m_memory kopiert,
     * aber nicht der Speicherbereich, auf den er zeigt (!).
     * Es gibt anschließend zwei Objekte von ZeichenketteF, deren Zeiger
     * m_memory auf denselben Speicherbereich zeigen.
     */
    ZeichenketteF(const ZeichenketteF& z) :
        m_memory(z.m_memory)
    {
    }

private:
    /*
     * Zuweisungsoperator.
     * 
     * Die Deklaration als "private" und die fehlende Definition sorgen
     * dafür, dass der Compiler eine Zuweisung mittels "=" nicht
     * zulässt und auch keinen Zuweisungsoperator implizit erzeugt.
     */
    ZeichenketteF& operator=(const ZeichenketteF& z);

    char *m_memory;
};

void scheitere()
{ 
    ZeichenketteF name("Wolfgang");
    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!
     * 
     * Sobald die Funktion scheitere() endet, wird für beide Objekte der
     * Destruktor aufgerufen. Der erste gibt den Speicherbereich frei,
     * auf den m_memory zeigt; der zweite versucht, denselben Speicher
     * nochmals freizugeben, was zu undefiniertem Verhalten führt.
     * Das kann z. B. ein Programmabsturz sein.
     */
}

Low copy cost

As can be seen in the example under Call, deep copies are made, which creates a certain burden. To avoid unnecessary load, we recommend two variants of the copying strategy shown above.

  • To share resources by means of reference counting in different instances; many implementations of the String class make use of this.
  • to adopt constant references as parameters in functions and methods in all cases in which parameters are only accessed for reading.

The copy constructor itself shows in its prototype how to avoid unnecessarily deep copies of objects that you only have to access for reading: It takes over a constant reference, otherwise it would have to be called (implicitly) before it is called! The signature "class name (const class name &)" is therefore typical.

See also