it-swarm.com.de

Was ist die Dreierregel?

  • Was bedeutet Kopieren eines Objekts?
  • Was sind der Kopierkonstruktor und der Kopierzuweisungsoperator?
  • Wann muss ich sie selbst deklarieren?
  • Wie kann ich verhindern, dass meine Objekte kopiert werden?
2036
fredoverflow

Einführung

C++ behandelt Variablen von benutzerdefinierten Typen mit Wertsemantik . Dies bedeutet, dass Objekte implizit in verschiedenen Kontexten kopiert werden, und wir sollten verstehen, was "Kopieren eines Objekts" tatsächlich bedeutet.

Betrachten wir ein einfaches Beispiel:

class person
{
    std::string name;
    int age;

public:

    person(const std::string& name, int age) : name(name), age(age)
    {
    }
};

int main()
{
    person a("Bjarne Stroustrup", 60);
    person b(a);   // What happens here?
    b = a;         // And here?
}

(Wenn Sie mit dem Teil name(name), age(age) verwirrt sind, wird dies als Elementinitialisierungsliste bezeichnet.)

Spezielle Mitgliedsfunktionen

Was bedeutet es, ein person Objekt zu kopieren? Die Funktion main zeigt zwei verschiedene Kopierszenarien. Die Initialisierung person b(a); wird vom Kopierkonstruktor durchgeführt. Seine Aufgabe besteht darin, ein neues Objekt auf der Grundlage des Zustands eines vorhandenen Objekts zu erstellen. Die Zuweisung b = a erfolgt durch den Kopierzuweisungsoperator . Ihre Aufgabe ist in der Regel etwas komplizierter, da sich das Zielobjekt bereits in einem gültigen Zustand befindet, der bearbeitet werden muss.

Da wir weder den Kopierkonstruktor noch den Zuweisungsoperator (noch den Destruktor) selbst deklariert haben, sind diese implizit für uns definiert. Zitat aus der Norm:

Der Kopierkonstruktor und der Kopierzuweisungsoperator [...] und der Destruktor sind spezielle Elementfunktionen. [ Hinweis : Die Implementierung deklariert diese Memberfunktionen implizit für einige Klassentypen, wenn das Programm sie nicht explizit deklariert. Die Implementierung definiert sie implizit, wenn sie verwendet werden. [...] Endnote ] [n3126.pdf Abschnitt 12 §1]

Standardmäßig bedeutet das Kopieren eines Objekts das Kopieren seiner Mitglieder:

Der implizit definierte Kopierkonstruktor für eine Nicht-Union-Klasse X führt eine memberweise Kopie seiner Unterobjekte aus. [n3126.pdf Abschnitt 12.8 §16]

Der implizit definierte Kopierzuweisungsoperator für eine Nicht-Union-Klasse X führt eine memberweise Kopierzuweisung ihrer Unterobjekte durch. [n3126.pdf Abschnitt 12.8 §30]

Implizite Definitionen

Die implizit definierten speziellen Elementfunktionen für person sehen folgendermaßen aus:

// 1. copy constructor
person(const person& that) : name(that.name), age(that.age)
{
}

// 2. copy assignment operator
person& operator=(const person& that)
{
    name = that.name;
    age = that.age;
    return *this;
}

// 3. destructor
~person()
{
}

Das memberweise Kopieren ist genau das, was wir in diesem Fall wollen: name und age werden kopiert, sodass wir ein in sich geschlossenes, unabhängiges person -Objekt erhalten. Der implizit definierte Destruktor ist immer leer. Dies ist auch in diesem Fall in Ordnung, da wir im Konstruktor keine Ressourcen beschafft haben. Die Destruktoren der Mitglieder werden implizit aufgerufen, nachdem der Destruktor person beendet ist:

Nachdem der Rumpf des Destruktors ausgeführt und alle im Rumpf zugewiesenen automatischen Objekte zerstört wurden, ruft ein Destruktor für Klasse X die Destruktoren für die direkten [...] Mitglieder von X auf [n3126.pdf 12.4 §6]

Ressourcen verwalten

Wann sollten wir diese speziellen Member-Funktionen explizit deklarieren? Wenn unsere Klasse eine Ressource verwaltet , dh wenn ein Objekt der Klasse für diese Ressource verantwortlich ist . Dies bedeutet normalerweise, dass die Ressource im Konstruktor erfasst (oder an den Konstruktor übergeben) und im Destruktor freigegeben wird.

Lassen Sie uns in der Zeit zurückgehen, in der wir uns mit C++ befasst haben. Es gab kein std::string, und Programmierer waren in Zeiger verliebt. Die Klasse person könnte folgendermaßen ausgesehen haben:

class person
{
    char* name;
    int age;

public:

    // the constructor acquires a resource:
    // in this case, dynamic memory obtained via new[]
    person(const char* the_name, int the_age)
    {
        name = new char[strlen(the_name) + 1];
        strcpy(name, the_name);
        age = the_age;
    }

    // the destructor must release this resource via delete[]
    ~person()
    {
        delete[] name;
    }
};

Selbst heute schreiben die Leute noch Klassen in diesem Stil und geraten in Schwierigkeiten: " Ich habe eine Person in einen Vektor geschoben und jetzt bekomme ich verrückte Speicherfehler! " Denken Sie daran, dass standardmäßig kopiert wird Ein Objekt bedeutet, dass seine Elemente kopiert werden, aber das Kopieren des Members name kopiert lediglich einen Zeiger, und nicht das Zeichenarray, auf das es zeigt! Dies hat mehrere unangenehme Auswirkungen:

  1. Änderungen über a können über b beobachtet werden.
  2. Sobald b zerstört ist, ist a.name ein baumelnder Zeiger.
  3. Wenn a zerstört wird, ergibt das Löschen des baumelnden Zeigers ndefiniertes Verhalten .
  4. Da bei der Zuweisung nicht berücksichtigt wird, auf was name vor der Zuweisung hingewiesen wurde, treten früher oder später überall Speicherlecks auf.

Explizite Definitionen

Da das memberweise Kopieren nicht den gewünschten Effekt hat, müssen wir den Kopierkonstruktor und den Kopierzuweisungsoperator explizit definieren, um tiefe Kopien des Zeichenarrays zu erstellen:

// 1. copy constructor
person(const person& that)
{
    name = new char[strlen(that.name) + 1];
    strcpy(name, that.name);
    age = that.age;
}

// 2. copy assignment operator
person& operator=(const person& that)
{
    if (this != &that)
    {
        delete[] name;
        // This is a dangerous point in the flow of execution!
        // We have temporarily invalidated the class invariants,
        // and the next statement might throw an exception,
        // leaving the object in an invalid state :(
        name = new char[strlen(that.name) + 1];
        strcpy(name, that.name);
        age = that.age;
    }
    return *this;
}

Beachten Sie den Unterschied zwischen Initialisierung und Zuweisung: Wir müssen den alten Zustand vor der Zuweisung zu name aufheben, um Speicherverluste zu vermeiden. Auch müssen wir uns vor Selbstzuweisung der Form x = x schützen. Ohne diese Prüfung würde delete[] name das Array löschen, das die Quellzeichenfolge enthält, da beim Schreiben von x = x sowohl this->name als auch that.name enthalten den gleichen Zeiger.

Ausnahmesicherheit

Leider schlägt diese Lösung fehl, wenn new char[...] eine Ausnahme aufgrund von Speichermangel auslöst. Eine mögliche Lösung besteht darin, eine lokale Variable einzuführen und die Anweisungen neu anzuordnen:

// 2. copy assignment operator
person& operator=(const person& that)
{
    char* local_name = new char[strlen(that.name) + 1];
    // If the above statement throws,
    // the object is still in the same state as before.
    // None of the following statements will throw an exception :)
    strcpy(local_name, that.name);
    delete[] name;
    name = local_name;
    age = that.age;
    return *this;
}

Dies übernimmt auch die Selbstvergabe ohne explizite Prüfung. Eine noch robustere Lösung für dieses Problem ist das Copy-and-Swap-Idiom , aber ich werde hier nicht auf die Details der Ausnahmesicherheit eingehen. Ich habe nur Ausnahmen erwähnt, um Folgendes zu verdeutlichen: Das Schreiben von Klassen zum Verwalten von Ressourcen ist schwierig.

Nicht kopierbare Ressourcen

Einige Ressourcen können oder sollten nicht kopiert werden, z. B. Dateihandles oder Mutexe. In diesem Fall deklarieren Sie einfach den Kopierkonstruktor und den Kopierzuweisungsoperator als private, ohne eine Definition anzugeben:

private:

    person(const person& that);
    person& operator=(const person& that);

Alternativ können Sie von boost::noncopyable erben oder sie als gelöscht deklarieren (in C++ 11 und höher):

person(const person& that) = delete;
person& operator=(const person& that) = delete;

Die Regel von drei

Manchmal müssen Sie eine Klasse implementieren, die eine Ressource verwaltet. (Verwalten Sie niemals mehrere Ressourcen in einer Klasse, da dies nur zu Schmerzen führt.) Beachten Sie in diesem Fall die Dreierregel :

Wenn Sie den Destruktor, den Kopierkonstruktor oder den Kopierzuweisungsoperator selbst explizit deklarieren müssen, müssen Sie wahrscheinlich alle drei explizit deklarieren.

(Leider wird diese "Regel" vom C++ - Standard oder einem mir bekannten Compiler nicht durchgesetzt.)

Die Regel von fünf

Ab C++ 11 verfügt ein Objekt über zwei zusätzliche spezielle Elementfunktionen: den Verschiebungskonstruktor und die Verschiebungszuweisung. Die Regel der fünf Staaten, um diese Funktionen auch zu implementieren.

Ein Beispiel mit den Unterschriften:

class person
{
    std::string name;
    int age;

public:
    person(const std::string& name, int age);        // Ctor
    person(const person &) = default;                // Copy Ctor
    person(person &&) noexcept = default;            // Move Ctor
    person& operator=(const person &) = default;     // Copy Assignment
    person& operator=(person &&) noexcept = default; // Move Assignment
    ~person() noexcept = default;                    // Dtor
};

Die Nullregel

Die Regel von 3/5 wird auch als die Regel von 0/3/5 bezeichnet. Der Nullteil der Regel besagt, dass Sie beim Erstellen Ihrer Klasse keine der speziellen Elementfunktionen schreiben dürfen.

Rat

In den meisten Fällen müssen Sie eine Ressource nicht selbst verwalten, da eine vorhandene Klasse wie std::string dies bereits für Sie erledigt. Vergleichen Sie einfach den einfachen Code mit einem std::string -Member mit der gewundenen und fehleranfälligen Alternative mit einem char*, und Sie sollten überzeugt sein. Solange Sie sich von rohen Zeigermitgliedern fernhalten, ist es unwahrscheinlich, dass die Dreierregel Ihren eigenen Code betrifft.

1683
fredoverflow

Die Dreierregel ist eine Faustregel für C++

Wenn deine Klasse etwas von braucht

  • einen Kopierkonstruktor ,
  • einen Zuweisungsoperator ,
  • oder ein Destruktor ,

explizit definiert, dann ist es wahrscheinlich alle drei von ihnen .

Der Grund dafür ist, dass alle drei normalerweise zum Verwalten einer Ressource verwendet werden. Wenn Ihre Klasse eine Ressource verwaltet, muss sie in der Regel sowohl das Kopieren als auch das Freigeben verwalten.

Wenn es keine gute Semantik für das Kopieren der von Ihrer Klasse verwalteten Ressource gibt, sollten Sie das Kopieren verbieten, indem Sie den Kopierkonstruktor und den Zuweisungsoperator deklarieren (nicht Definieren) als private.

(Beachten Sie, dass die bevorstehende neue Version des C++ - Standards (C++ 11) die Verschiebungssemantik zu C++ hinzufügt, was wahrscheinlich die Dreierregel ändern wird. Ich weiß jedoch zu wenig darüber, um einen C++ 11-Abschnitt zu schreiben über die Dreierregel.)

480
sbi

Das Gesetz der großen Drei ist wie oben angegeben.

Ein einfaches Beispiel für die Art des Problems, das es löst, im Klartext:

Nicht standardmäßiger Destruktor

Sie haben Speicher in Ihrem Konstruktor zugewiesen und müssen daher einen Destruktor schreiben, um ihn zu löschen. Andernfalls führt dies zu einem Speicherverlust.

Sie könnten denken, dass dies Arbeit geleistet ist.

Das Problem ist, dass, wenn eine Kopie Ihres Objekts erstellt wird, die Kopie auf denselben Speicher verweist wie das ursprüngliche Objekt.

Sobald einer von diesen den Speicher in seinem Destruktor löscht, hat der andere einen Zeiger auf ungültigen Speicher (dies wird als baumelnder Zeiger bezeichnet), wenn er versucht, ihn zu verwenden, werden die Dinge haarig.

Aus diesem Grund schreiben Sie einen Kopierkonstruktor, der neuen Objekten eigene Speicherbereiche zuweist, die zerstört werden sollen.

Zuweisungsoperator und Kopierkonstruktor

Sie haben einem Memberzeiger Ihrer Klasse in Ihrem Konstruktor Speicher zugewiesen. Wenn Sie ein Objekt dieser Klasse kopieren, kopieren der Standardzuweisungsoperator und der Kopierkonstruktor den Wert dieses Elementzeigers in das neue Objekt.

Dies bedeutet, dass das neue Objekt und das alte Objekt auf dasselbe Speicherelement zeigen. Wenn Sie es also in einem Objekt ändern, wird es auch für das andere Objekt geändert. Wenn ein Objekt diesen Speicher löscht, versucht das andere, ihn zu verwenden - eek.

Um dies zu beheben, schreiben Sie Ihre eigene Version des Kopierkonstruktors und des Zuweisungsoperators. Ihre Versionen weisen den neuen Objekten separaten Speicher zu und kopieren die Werte, auf die der erste Zeiger zeigt, anstelle der Adresse.

151
Stefan

Grundsätzlich bedeutet ein Destruktor (nicht der Standard-Destruktor), dass die von Ihnen definierte Klasse über eine gewisse Speicherzuordnung verfügt. Angenommen, die Klasse wird außerhalb von Client-Code oder von Ihnen verwendet.

    MyClass x(a, b);
    MyClass y(c, d);
    x = y; // This is a shallow copy if assignment operator is not provided

Wenn MyClass nur einige primitiv typisierte Elemente enthält, funktioniert ein Standardzuweisungsoperator. Wenn MyClass jedoch Zeigerelemente und Objekte enthält, die keine Zuweisungsoperatoren enthalten, ist das Ergebnis unvorhersehbar. Daher können wir sagen, dass, wenn im Destruktor einer Klasse etwas zu löschen ist, wir möglicherweise einen Deep-Copy-Operator benötigen, was bedeutet, dass wir einen Copy-Konstruktor und einen Zuweisungsoperator bereitstellen sollten.

42
fatma.ekici

Was bedeutet das Kopieren eines Objekts? Es gibt einige Möglichkeiten, wie Sie Objekte kopieren können - lassen Sie uns über die beiden Arten sprechen, auf die Sie sich am wahrscheinlichsten beziehen - Deep Copy und Shallow Copy.

Da wir in einer objektorientierten Sprache sind (oder dies zumindest annehmen), nehmen wir an, Sie haben ein Stück Speicher zugewiesen. Da es sich um eine OO-Sprache handelt, können wir leicht auf von uns zugewiesene Speicherbereiche verweisen, da es sich normalerweise um von uns definierte primitive Variablen (Ints, Chars, Bytes) oder Klassen handelt, die aus unseren eigenen Typen und Primitiven bestehen. Nehmen wir also an, wir haben eine Klasse von Autos wie folgt:

class Car //A very simple class just to demonstrate what these definitions mean.
//It's pseudocode C++/Javaish, I assume strings do not need to be allocated.
{
private String sPrintColor;
private String sModel;
private String sMake;

public changePaint(String newColor)
{
   this.sPrintColor = newColor;
}

public Car(String model, String make, String color) //Constructor
{
   this.sPrintColor = color;
   this.sModel = model;
   this.sMake = make;
}

public ~Car() //Destructor
{
//Because we did not create any custom types, we aren't adding more code.
//Anytime your object goes out of scope / program collects garbage / etc. this guy gets called + all other related destructors.
//Since we did not use anything but strings, we have nothing additional to handle.
//The assumption is being made that the 3 strings will be handled by string's destructor and that it is being called automatically--if this were not the case you would need to do it here.
}

public Car(const Car &other) // Copy Constructor
{
   this.sPrintColor = other.sPrintColor;
   this.sModel = other.sModel;
   this.sMake = other.sMake;
}
public Car &operator =(const Car &other) // Assignment Operator
{
   if(this != &other)
   {
      this.sPrintColor = other.sPrintColor;
      this.sModel = other.sModel;
      this.sMake = other.sMake;
   }
   return *this;
}

}

Eine tiefe Kopie liegt vor, wenn wir ein Objekt deklarieren und dann eine vollständig separate Kopie des Objekts erstellen. Am Ende befinden sich 2 Objekte in 2 vollständigen Speichersätzen.

Car car1 = new Car("mustang", "ford", "red");
Car car2 = car1; //Call the copy constructor
car2.changePaint("green");
//car2 is now green but car1 is still red.

Jetzt machen wir etwas Seltsames. Angenommen, car2 ist entweder falsch programmiert oder soll absichtlich den tatsächlichen Speicher teilen, aus dem car1 besteht. (Es ist normalerweise ein Fehler, dies zu tun, und in Klassen ist es normalerweise die Decke, unter der es diskutiert wird.) Stellen Sie sich vor, Sie lösen jedes Mal, wenn Sie nach car2 fragen, einen Zeiger auf den Speicherplatz von car1 auf ... das ist mehr oder weniger eine flache Kopie ist.

//Shallow copy example
//Assume we're in C++ because it's standard behavior is to shallow copy objects if you do not have a constructor written for an operation.
//Now let's assume I do not have any code for the assignment or copy operations like I do above...with those now gone, C++ will use the default.

 Car car1 = new Car("ford", "mustang", "red"); 
 Car car2 = car1; 
 car2.changePaint("green");//car1 is also now green 
 delete car2;/*I get rid of my car which is also really your car...I told C++ to resolve 
 the address of where car2 exists and delete the memory...which is also
 the memory associated with your car.*/
 car1.changePaint("red");/*program will likely crash because this area is
 no longer allocated to the program.*/

Seien Sie also unabhängig von der Sprache, in der Sie schreiben, sehr vorsichtig, was Sie damit meinen, wenn Sie Objekte kopieren, da Sie die meiste Zeit eine ausführliche Kopie wünschen.

Was sind der Kopierkonstruktor und der Kopierzuweisungsoperator? Ich habe sie oben schon benutzt. Der Kopierkonstruktor wird aufgerufen, wenn Sie Code wie Car car2 = car1; eingeben. Wenn Sie eine Variable deklarieren und in einer Zeile zuweisen, wird der Kopierkonstruktor aufgerufen. Der Zuweisungsoperator ist das, was passiert, wenn Sie ein Gleichheitszeichen --car2 = car1; verwenden. Hinweis car2 wird nicht in derselben Anweisung deklariert. Die beiden Codeblöcke, die Sie für diese Vorgänge schreiben, sind wahrscheinlich sehr ähnlich. Tatsächlich hat das typische Entwurfsmuster eine andere Funktion, die Sie aufrufen, um alles festzulegen, sobald Sie zufrieden sind. Die ursprüngliche Kopie/Zuweisung ist legitim. Wenn Sie sich den von mir geschriebenen Longhand-Code ansehen, sind die Funktionen nahezu identisch.

Wann muss ich sie selbst deklarieren? Wenn Sie keinen Code schreiben, der freigegeben oder in irgendeiner Weise für die Produktion verwendet werden soll, müssen Sie ihn nur deklarieren, wenn Sie ihn benötigen. Sie müssen sich darüber im Klaren sein, was Ihre Programmiersprache tut, wenn Sie sie "aus Versehen" verwenden und keine gemacht haben - d. H. Sie erhalten die Compiler-Standardeinstellung. Ich verwende zum Beispiel selten Kopierkonstruktoren, aber Zuweisungsoperatorüberschreibungen sind sehr häufig. Wussten Sie, dass Sie auch überschreiben können, was Addition, Subtraktion usw. bedeuten?

Wie kann ich verhindern, dass meine Objekte kopiert werden? Das Überschreiben aller Möglichkeiten, mit denen Sie Speicher für Ihr Objekt zuweisen dürfen, mit einer privaten Funktion ist ein vernünftiger Anfang. Wenn Sie wirklich nicht möchten, dass Benutzer sie kopieren, können Sie dies öffentlich machen und den Programmierer warnen, indem Sie eine Ausnahme auslösen und das Objekt auch nicht kopieren.

35
user1701047

Wann muss ich sie selbst deklarieren?

Die Dreierregel besagt, dass, wenn Sie eines von a deklarieren

  1. kopierkonstruktor
  2. zuweisungsoperator kopieren
  3. zerstörer

dann solltest du alle drei deklarieren. Es entstand aus der Beobachtung, dass die Notwendigkeit, die Bedeutung eines Kopiervorgangs zu übernehmen, fast immer von der Klasse herrührte, die eine Art Ressourcenmanagement durchführte, und das bedeutete fast immer, dass dies der Fall war

  • welche Ressourcenverwaltung auch immer in einem Kopiervorgang ausgeführt wurde, musste wahrscheinlich in dem anderen Kopiervorgang ausgeführt werden

  • der Klassendestruktor ist auch an der Verwaltung der Ressource beteiligt (und gibt sie normalerweise frei). Die klassische Ressource, die verwaltet werden sollte, war der Arbeitsspeicher. Aus diesem Grund deklarieren alle Standardbibliotheksklassen, die den Arbeitsspeicher verwalten (z. B. die STL-Container, die die dynamische Speicherverwaltung ausführen), alle die "großen Drei": sowohl Kopiervorgänge als auch einen Destruktor.

Eine Konsequenz der Dreierregel bedeutet, dass das Vorhandensein eines vom Benutzer deklarierten Destruktors darauf hinweist, dass eine einfache Kopie für Mitglieder wahrscheinlich nicht für die Kopiervorgänge in der Klasse geeignet ist. Dies legt wiederum nahe, dass die Kopiervorgänge, wenn eine Klasse einen Destruktor deklariert, wahrscheinlich nicht automatisch generiert werden sollten, da sie nicht das Richtige tun würden. Zum Zeitpunkt der Einführung von C++ 98 wurde die Bedeutung dieser Argumentation nicht vollständig gewürdigt. Daher hatte das Vorhandensein eines vom Benutzer deklarierten Destruktors in C++ 98 keinen Einfluss auf die Bereitschaft der Compiler, Kopiervorgänge zu generieren. Dies ist in C++ 11 weiterhin der Fall, aber nur, weil eine Einschränkung der Bedingungen, unter denen die Kopiervorgänge generiert werden, zu viel veralteten Code beschädigen würde.

Wie kann ich verhindern, dass meine Objekte kopiert werden?

Deklarieren Sie den Kopierkonstruktor und den Kopierzuweisungsoperator als privaten Zugriffsbezeichner.

class MemoryBlock
{
public:

//code here

private:
MemoryBlock(const MemoryBlock& other)
{
   cout<<"copy constructor"<<endl;
}

// Copy assignment operator.
MemoryBlock& operator=(const MemoryBlock& other)
{
 return *this;
}
};

int main()
{
   MemoryBlock a;
   MemoryBlock b(a);
}

Ab C++ 11 können Sie auch den Kopierkonstruktor und den Zuweisungsoperator als gelöscht deklarieren

class MemoryBlock
{
public:
MemoryBlock(const MemoryBlock& other) = delete

// Copy assignment operator.
MemoryBlock& operator=(const MemoryBlock& other) =delete
};


int main()
{
   MemoryBlock a;
   MemoryBlock b(a);
}
24
Ajay yadav

Viele der vorhandenen Antworten betreffen bereits den Kopierkonstruktor, den Zuweisungsoperator und den Destruktor. In Post-C++ 11 kann die Einführung der Verschiebungssemantik dies jedoch über 3 hinaus erweitern.

Kürzlich hielt Michael Claisse einen Vortrag zu diesem Thema: http://channel9.msdn.com/events/CPP/C-PP-Con-2014/The-Canonical-Class

14
wei

Die Dreierregel in C++ ist ein grundlegendes Prinzip für den Entwurf und die Entwicklung von drei Anforderungen: Wenn in einer der folgenden Elementfunktionen eine eindeutige Definition vorliegt, sollte der Programmierer die beiden anderen Elementfunktionen zusammen definieren. Die folgenden drei Mitgliedsfunktionen sind nämlich unverzichtbar: Destruktor, Kopierkonstruktor, Kopierzuweisungsoperator.

Der Copy-Konstruktor in C++ ist ein spezieller Konstruktor. Es wird verwendet, um ein neues Objekt zu erstellen. Dabei handelt es sich um das neue Objekt, das einer Kopie eines vorhandenen Objekts entspricht.

Der Zuweisungsoperator "Kopieren" ist ein spezieller Zuweisungsoperator, mit dem in der Regel ein vorhandenes Objekt für andere Objekte desselben Objekttyps angegeben wird.

Es gibt kurze Beispiele:

// default constructor
My_Class a;

// copy constructor
My_Class b(a);

// copy constructor
My_Class c = a;

// copy assignment operator
b = a;
9
Marcus Thornton