was ist genau der Sinn des Copykonstruktors



  • anonymus schrieb:

    Solange nur bekannte Objekte (also die eingebauten Datentypen wie int, float,
    char) usw. verwendet werden, hat der Compiler kein Problem, eine Kopie von einem
    Objekt zu erstellen:
    Er kopiert einfach alles Bit für Bit vom alten ins neue Objekt.

    Was aber passiert, wenn z. B. Zeiger in einer Klasse als Membervariablen
    vorhanden sind?

    Genau das allergleiche:
    Der Kompiler kopiert Bit für Bit vom alten ins neue Objekt.

    Dumm gelaufen:
    Jetzt haben beide Objekte einen Zeiger auf die selben Daten.

    Und hier kommt der Kopierkonstruktor ins Spiel:
    er wird, falls vorhanden genau hier aufgerufen.
    Somit hast du die Möglichkeit, selbst zu entscheiden, wie kopiert wird.
    Normalerweise wird jetzt für das neue Objekt auch neuer Speicher für
    die Daten zugewiesen und die Daten werden vom alten ins neue Objekt reinkopiert.

    Somit sind beide Objekte auch wirklich eigenständig.

    Das sind dann Shallow Copy und Deep Copy wenn ich das richtig verstanden habe. 😃





  • Man sollte noch etwas genauer zwischen Copy-Konsturktor und operator= unterscheiden:

    Der Copykonstruktor legt ein Völlig neues Objekt an und initialisiert dessen Membervariablen, ändert evtl. danach noch die eine oder andere.
    Der operator= ist eine normale Methode und kann daher nur für bereits initialisierte Objekte aufgerufen werden. Der copy-konstruktor ist daher im Grunde schneller, wenn man ein neues Objekt erzeugen will, da für den operator= erst ein anderer Konstruktor aufgerufen werden müsste, der nur Zeit frisst.
    Der Copy-konstruktor und der operator= werden im Übrigen vom Compiler selbst erzeugt, wenn sie nicht definiert wurden und das Programm irgendwo implizit oder explizit einen Kopiervorgang verlangt. Zum Beispiel werden bei Funktionen, deren Parameter per Wert übergeben werden, diese Parameter kopiert, anders als bei der Parameterübergabe per Referenz.
    Wenn man also nichttriviale Klassen schreibt, sollte man sich immer Gedanken über copy-Ctor und operator= machen. Wenn bitweises Kopieren genügt, überlässt man die arbeit dem Compiler und macht an entsprechender Stelle im header evtl. ne kleine Notiz. Genügt das nicht, dann muss man die beiden entweder selbst definieren (wenns ne sinnvolle Umsetzung gibt) oder aber als private deklarieren und nicht definieren, um ihren gebrauch zu verhindern.



  • Wenn bitweises Kopieren genügt, überlässt man die arbeit dem Compiler und macht an entsprechender Stelle im header evtl. ne kleine Notiz

    Da der Standard-Copy-Ctor keine bitweise Kopie erzeugt ist dieser Hinweis irreführend. Richtig wäre: wenn eine Member-weise Kopie korrekt ist, reicht der Standard-Copy-Ctor.

    Er kopiert einfach alles Bit für Bit vom alten ins neue Objekt.

    Nope. Er kopiert Member-für-Member.

    Hier verhält es sich ganz ähnlich.
    mit

    Obj1 = Obj2;
    

    wird standardmäßig alles Bit für Bit von Obj2 nach Obj1 kopiert

    Nope. Hier wird Member-für-Member zugewiesen.

    Bitweise werden POD-Typen kopiert. Alle anderen werden per Copy-Ctor kopiert.
    Analoges gilt für den operator=.



  • Mir fällt gerade auf, dass ich natürlich voreilig Unsinn geschrieben habe. Im a=b-Fall bei 2 initialisierten Objekten wird natürlich nicht der Kopierkonstruktor aufgerufen, weil beide Objekte ja schon konstruiert sind. Aber im Beispiel von Mr. Volkard ist ja plausibel dargelegt, wieso es notwendig sein kann, einen eigenen Kopierkonstruktor zu definieren. 😉

    class1 a , b ;
    a = b ; // Zuweisungsoperator
    
    class1 a;
    class1 b(a) // Kopierkonstruktor (b wird mit a als Vorlage erstellt);
    
    class1 a;
    
    void machwas(class1 arg) {}
    
    int main() {
        machwas(a); // Ebenfalls Kopierkonstruktor zur Parameterübergabe
    }
    


  • HumeSikkins schrieb:

    Er kopiert einfach alles Bit für Bit vom alten ins neue Objekt.

    Nope. Er kopiert Member-für-Member.

    char * p1 = ...;
    char * p2;
    
    p2 = p1;
    

    hm, ok du chef, ich nix,
    aber wo ist der Unterschied zwischen "p2 wird p1 zugewiesen" und
    "p1 wird Bit für Bit nach p2 kopiert"
    (bis auf das, dass natürlich nicht jedes Bit einzeln kopiert wird, sondern
    beim 32 Bit Prozi 32 Bit gleichzeitig)

    Ergebnis ist doch das gleiche?



  • @anonymus
    Mir scheint du hast meinen Beitrag nicht verstanden. Der automatisch generierte Copy-Ctor kopiert Member-Für-Member. POD-Typen werden dabei bitweise kopiert. Alle anderen wiederum durch aufruf ihres Copy-Ctors.

    In dem von dir geposteten Code wird weder ein Copy-Ctor generiert noch einer aufgerufen. Dort wird in der Tat nur die Adresse kopiert, so dass p2 nachher auf das selbe zeigt wie p1.

    Ergebnis ist doch das gleiche?

    Nein ist es nicht.

    struct X {
        std::string s;
    };
    
    ...
    X x1;
    X x2(x1);
    

    Würde hier, wie behauptet, bitweise kopiert werden, würde dies zu unendlich viel Schmerz führen. Da aber nicht bitweise kopiert wird, gibt es keinen Schmerz und man muss für X auch keinen Copy-Ctor erstellen.



  • ok,
    bin überzeugt 🙂

    danke



  • Ich weiß nicht ob das schon einer geschrieben hat aber bei der Initialisierung eines Objekts wir auch der Kopierkonstruktor aufgerufen...

    MyClass a;
    MyClass b = a;
    


  • ja, da schon, aber das ist kein anderer fall als

    Maclass b(a);
    

    nur ne andre schreibweise 😉

    //edit
    boah hume hat 9999 beiträge 😮



  • Noch ein Post mehr und er bekommt 'nen Keks. 🙂


Anmelden zum Antworten