Shallow und Deep Copying



  • icarus2 schrieb:

    ...
    Das Hauptproblem ist ja, ...

    Das Hauptproblem wovon?

    icarus2 schrieb:

    ...
    Wiso macht C++ nicht immer ein deep copying? ...

    Ich halte Deine Grundthese für falsch. C++ macht nicht "immer eine shallow copy", sondern kopiert eben genau das, was es in der Hand hat: Einen string, ein Objekt, .... oder eben einen Zeiger.
    Ein Zeiger ist eben nicht dasselbe wie das Objekt, auf das er zeigt. Es ist ein Verweis.

    Mal umgedreht (Einmal angenommen, C++ würde bei Pointerkopie automatisch ein neues Objekt erstellen) - was würde bei folgendem Code passieren?

    MyObject m;
    MyObject* p1(&m);
    MyObject* p2(&m);
    if(p1 == p2) cout << "was wir erwarten würden\n";
    else cout << "Hoppla\n";
    
    p2 = p1; // Nach Deiner Theorie müsste hier ein 
    // neues Objekt erzeugt werden, auf das p2 dann zeigt.
    
    if(p1 == p2) cout << "was wir erwarten würden\n";
    else cout << "Hoppla\n";
    // hier müsste nun "Hoppla" rauskommen, weil p1 und p2 
    // nicht mehr auf dasselbe Objekt zeigen.
    

    Das wäre extremer Quark.
    (Genaugenommen wäre es wohl schon unmöglich, überhaupt einem Zeiger die Adresse eines Objekts zuzuweisen ... weil ja jedesmal ein neues Objekt angelegt würde)

    Gruß,

    Simon2.



  • Das Hauptproblem wovon?

    Naja, Problem ist wohl etwas das falsche Wort. Besser gesagt, die Tatsache, dass man in gewissen Fällen den Copy Constructor usw. überschreiben muss. (Siehe Code-Beispiele von mir).

    Ich halte Deine Grundthese für falsch. C++ macht nicht "immer eine shallow copy", sondern kopiert eben genau das, was es in der Hand hat: Einen string, ein Objekt, .... oder eben einen Zeiger.

    Also wenn ich das richtig verstanden habe wurde im C++ Primer gesagt, dass C++ ein shallow copying macht (zumindest in den Beispielen, um die es in meinen Beispielen geht). So wie ich das verstanden habe ist es ein shallow copying, weil nur die Adresse übergeben wird. Der neue Pointer wird ja nicht mit new erzeugt oder liege ich da falsch? (hoffe, ich konnte mich verständlich ausdrücken ^^).
    Ich habe nocht nicht so den Überblick und wollte nur verstehen, wiso es von den C++ Entwicklern so gemacht wurde.



  • icarus2 schrieb:

    ...Besser gesagt, die Tatsache, dass man in gewissen Fällen den Copy Constructor usw. überschreiben muss. ...

    Nunja, man muss eben genau da einen CopyCtor o.ä. bereitstellen, wo es eben nicht eindeutig ist, wie kopiert werden soll.
    In vielen Fällen ist es das aber.

    Was der Primer nun genau damit meint, dass "C++ ein shallow copying macht", weiß ich nicht. Aber es sollte mich sehr wundern, wenn dort stünde, dass "C++ IMMER NUR ein shallow copying macht", weil das einfach nicht stimmt.
    Vermutlich geht es da eher um einen speziellen Fall.

    Nur mal zur Erklärung:

    icarus2 schrieb:

    ...Der neue Pointer wird ja nicht mit new erzeugt ...

    Da meinst Du bestimmt: "...Das neue Objekt wird nicht mit new erzeugt...". ... und ich glaube, der Unterschied ist schon ein wichtiger Auslöser für Deine Verwirrung.
    Ein Zeiger auf ein Objekt ist eben etwas ganz Anderes als das Objekt selbst (So wie eine Hausanschrift etwas ganz Anderes ist als ein Haus).

    Außerdem scheinst Du "Zeiger" mit "dynamischer Objekterzeugung" zu vermengen. Letzteres ist aber nur ein spezieller (und kleiner) Anwendungsbereich von Zeigern. Bei dynamischer Objekterzeugung sagst Du als Programmierer: "Ich will irgendwann zur Laufzeit selbst bestimmen, ob und wann und wie ich ein Objekt erzeugen will" - und dass Du in dem Fall das dann auch machen musst (z.B. durch einen selbstgeschriebenen CopyCtor) , ist IMHO weder verwunder- noch verwerflich. 😉
    Bei Java ist das übrigens nicht anders.
    Mal so gesagt: Kein Compiler der Welt kann von sich aus (ohne, dass Du es ihm sagst) wissen, ob Du
    a) ein neues Objekt haben möchtest oder
    b) ob Dein Zeiger auf ein bereits bestehendes zeigen soll.

    Zusammenfassung: Es gibt eine Menge Anwendungsfälle von Zeigern und man muss sich nur um das Kopieren kümmern, wenn man nicht den "Standardweg" gehen möchte.
    Deshalb ist es sinnlos und nicht möglich, diese Arbeit über eine "automatischer deep copy bei Zeigern" abzuwickeln.

    Gruß,

    Simon2.



  • Ja, dann war das "shallow copying" wohl nur auf einen Anwendungsfall bezogen und ich habe das nicht ganz mitbekommen.

    Deine Erklärung hat mir sehr geholfen. Ich glaube ich sollte das Ganze jetzt besser verstehen.

    Vielen Dank 🙂



  • icarus2 schrieb:

    Ja, dann war das "shallow copying" wohl nur auf einen Anwendungsfall bezogen und ich habe das nicht ganz mitbekommen.

    Nein, "shallow copying" wird als ein synonymer Begriff für "memberwise copying" verwendet und auf den implizit erzeugten Copy-Konstruktor bezogen. D.h. die Aussage ist völlig korrekt und steht fast 1:1 so im Standard.

    Nebenbei, wenn du schon zu einem C++ Primer greifst, dann doch lieber zum Buch von Lippman. Der ist die wesentlich kompetentere Kapazität auf diesem Gebiet. Obwohl man zugeben muss, dass Stephen Prata nicht unbedingt ein schlechter Autor ist.



  • Nein, "shallow copying" wird als ein synonymer Begriff für "memberwise copying" verwendet und auf den implizit erzeugten Copy-Konstruktor bezogen. D.h. die Aussage ist völlig korrekt und steht fast 1:1 so im Standard.

    Ok, jetzt steht Aussage gegen Aussage ^^

    Nebenbei, wenn du schon zu einem C++ Primer greifst, dann doch lieber zum Buch von Lippman. Der ist die wesentlich kompetentere Kapazität auf diesem Gebiet. Obwohl man zugeben muss, dass Stephen Prata nicht unbedingt ein schlechter Autor ist.

    Bin mit dem C++ Primer Plus eigentlich sehr zufrieden.

    Btw... schicker Name 😉



  • Mitleid schrieb:

    ...Nein, "shallow copying" wird als ein synonymer Begriff für "memberwise copying" verwendet und auf den implizit erzeugten Copy-Konstruktor bezogen....

    😕
    Habe ich so noch nicht gehört (was nicht viel bedeutet)....
    Was ist denn dann das Gegenteil von "shallow copying"?

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Habe ich so noch nicht gehört (was nicht viel bedeutet)....
    Was ist denn dann das Gegenteil von "shallow copying"?

    Ich zitiere mal die Stelle, damit klar wird, was das Buch meint um eine Diskussionsgrundlage herzustellen. Scheint nämlich, als hätten hier einige unterschiedliche Vorstellungen von dem Begriff "shallow copying".

    Stephen Prata, C++ Primer plus schrieb:

    The default copy constructor performs a member-by-member copy of the nonstatic members (memberwise copying, also sometimes called shallow copying). Each member is copied by value.

    Ich denke damit ist dann (hoffentlich) alles klar. 🙂
    Was meinst du hier mit "Gegenteil"?

    icarus2 schrieb:

    Ok, jetzt steht Aussage gegen Aussage ^^

    Wir haben hier neben dem Standard keine anderen Götter. Es steht also nicht wirklich Aussage gegen Aussage. 😃



  • Mitleid schrieb:

    ...Ich zitiere mal die Stelle, damit klar wird, was das Buch meint um eine Diskussionsgrundlage herzustellen. ....

    Danke! 😃

    "... memberwise copying, also sometimes called shallow copying..." - nunja; deckt sich wahrlich nicht mit Irgendetwas, was ich bislang gehört habe.

    Mitleid schrieb:

    ...Was meinst du hier mit "Gegenteil"?...

    Nunja zum Einen: Wenn ein "copying" durch das Attribut "shallow" beschrieben wird, legt das nahe, dass es außerdem noch eine andere Form gibt.
    Zum Anderen: Ich kenne die deutschen Ausdrücke "flache Kopie" und "tiefe Kopie", die eine Art Gegensatzpaar bilden und die eigentlich nur bei "verknüpften" Objekten sinnvoll ist.

    struct B;
    
    struct A {
       B* b;
       void init() { b = new B; } // schlechtes Coding; dient nur als Beispiel hierfür
    };
    
    void flacheKopie(A& von, A& nach) {
       nach.b = von.b;
    }
    
    void tiefeKopie(A& von, A& nach) {
       nach.b = new B(von.b); // CpyCtor von B vorausgesetzt
    }
    

    Dabei hatte ich "shallow copying" in die Schublade "flache Kopie" gesteckt.

    Aber vielleicht meint der Autor hier, dass keine neuen Objekte angelegt, sondern lediglich operator=() aufgerufen werden ...

    Gruß,

    Simon2.


Anmelden zum Antworten