Kopier-Konstruktor



  • Hallo zusammen,

    ich habe folgendes Problem. Ich wollte mein eigenen Kopier-Konstruktor schreiben, um eine tiefe Kopie durchzuführen. Allerdings gibt mein Code immer noch 47 und 47 aus, obwohl ich 47 und erwarte. Das gleiche Problem hatte ich schonmal. Könnte mir da jemand weiterhelfen?

    Vielen Dank!

    #include <iostream>
    class Point{
    private:
        int* coordinates;
    
        static int* make_pair(int x, int y){
            int* result = new int[2]{x,y};
            return result;
        }
    public:
        Point(int x, int y): coordinates(make_pair(x,y)){}
        
        int get_x()const{
            return coordinates[0];
        }
    
    
        int get_y()const{
            return coordinates[1];
        }
    
    
        int set_x(int x) const{
            this-> coordinates[0]=coordinates[0];
        }
    
        int set_y(int y)const {
            this-> coordinates[1]=coordinates[1];
        }
    
        Point(const Point& other):Point(other.get_x(), other.get_y()){}
    };
    
    int main () {
        Point p(47,11);
        Point p_copy = p;
        p.set_x(23);
        std::cout<<p_copy.get_x() << " " << p.get_x() << std::endl;
    }
    


  • Deine set_x und set_y Funktionen tun nicht das, was sie sollen.

    Btw:
    Du brauchst auch noch einen Destruktor, der den im Konstruktor allokierten Speicher wieder freigibt.


  • Mod

    Vielleicht sollten deine Setter auch was setzen? Schalte Compilerwarnungen auf Maximum und sieh jede Warnung als einen Fehler an.

    Ansonsten machst du so ungefähr alles falsch, was immer alle falsch machen, wenn sie mit mit dynamischen Speicher rumspielen. Siehe https://en.cppreference.com/w/cpp/language/rule_of_three
    Die wichtigste Regel ist die Rule of 0, ganz unten, nämlich dass das alles komplett unnötig ist. Wie wäre es mit int coordinates[2];?



  • @SeppJ sagte in Kopier-Konstruktor:

    ...
    Ansonsten machst du so ungefähr alles falsch, was immer alle falsch machen, wenn sie mit mit dynamischen Speicher rumspielen. Siehe https://en.cppreference.com/w/cpp/language/rule_of_three
    Die wichtigste Regel ist die Rule of 0, ganz unten, nämlich dass das alles komplett unnötig ist. Wie wäre es mit int coordinates[2];?

    Vllt ist hier der Weg das Ziel?



  • Hallo @Johnny01
    Warum ein Array auf dem Heap? Nimm doch x und y als Attribut welchen Typs auch immer (reicht integer?).
    Dem jeweiligen 'setter" übergibst Du einfach einen Wert, der einfach zugewiesen wird.
    Der jeweilige 'getter" liefert einfach x odery.
    Der Kopier-Konstruktor überträgt einfach nur:

    Point( const Point & other ) : x( other.x ), y( other.y ) {}
    


  • Der Titel ist "Kopier-Konstruktor".

    Vielleicht möchte TE das lernen und hat deswegen ein Beispiel gewählt, das einen expliziten Kopierkonstruktor erfordert. Bei einem array oder zwei expliziten Member-Variablen, die auf dem Stack liegen, kann er so einfach keinen Fehlerfall erzeugen, weil der Default-Kopierkonstruktor alles richtig macht. In seinem Beispiel tut er das nicht, da muss er was tun, damit der Kopierkonstruktor funktioniert.


  • Mod

    @DocShoe sagte in Kopier-Konstruktor:

    @SeppJ sagte in Kopier-Konstruktor:

    ...
    Ansonsten machst du so ungefähr alles falsch, was immer alle falsch machen, wenn sie mit mit dynamischen Speicher rumspielen. Siehe https://en.cppreference.com/w/cpp/language/rule_of_three
    Die wichtigste Regel ist die Rule of 0, ganz unten, nämlich dass das alles komplett unnötig ist. Wie wäre es mit int coordinates[2];?

    Vllt ist hier der Weg das Ziel?

    Dann wäre OP ganz schön auf dem Holzweg, weswegen der Hinweis auf Rule of 3/5 um so wichtiger ist.



  • Dann frage ich mal @Johnny01; was willst Du eigentlich?
    Eine Point Klasse oder üben wie ich mit Arrays auf dem Heap umgehen muss oder ist es eine Ausbildungsaufgabe?



  • @SeppJ

    Vllt erarbeitet er sich das gerade?

    Edit:
    Wir machen hier alle Annahmen, ab Besten sagt TE, war er erreichen möchte.


  • Mod

    @DocShoe sagte in Kopier-Konstruktor:

    @SeppJ

    Vllt erarbeitet er sich das gerade?

    Ja? Und dann sage ich, wie's richtig geht? Was ein Faux-Pas!



  • @SeppJ sagte in Kopier-Konstruktor:

    @DocShoe sagte in Kopier-Konstruktor:

    @SeppJ

    Vllt erarbeitet er sich das gerade?

    Ja? Und dann sage ich, wie's richtig geht? Was ein Faux-Pas!

    ...


  • Mod

    @DocShoe Ich verstehe, was Du meinst, aber soweit ich vom OP erkennen kann hat der TE sich nicht zu Studienzwecken gezielt mit copy ctors auseinandergesetzt, sondern wollte einfach seine Klasse kopierbar machen. Es ist IMHO mehr als adäquat ihn auf eine sowohl einfachere und zugleich überlegene Lösung hinzuweisen?



  • Eigentlich wäre es von @Johnny01 fair, wenn er sich dazu äußern würde, oder?



  • @Helmut-Jakoby in welchen Punkt äußern?



  • @Johnny01
    Die meisten Programme lassen sich grob in 4 Richtungen unterscheiden:

    1.) Schulprogramme
    Schulprogramme sind Programme, welche an der Schule gelehrt werden und welche fast immer hoffnungslos veraltet sind. Da werden Pointer, verkettete Listen,... benutzt.

    Möchte man hier helfen, so muss man erst einmal schauen was der Lehrer haben möchte und eine entsprechende Lösung zeigen. Egal wie veraltet, fehleranfällig die Lösung sein mag.

    2.) Uniprogramme
    Uniprogramme sind relativ ähnlich zu Schulprogrammen. Jedoch hat man mehr Freiheiten beim programmiern, hauptsache das Ergebnis stimmt.

    Und an meiner Uni wurde immer gesagt, man lehre keine Programmierung, das darf man schön selbst machen. Also bekam man öfters eine sehr kurze Einführung in Java, C,... und durfte dann direkt ein Problem nachprogrammieren.

    3.) Programmiersprache als MIttel zum Zweck
    Beispiel: "Hmm, der angebotene Kredit hat einen Zinssatz von 2% und eine Laufzeit von 8 Jahren. Der zweite angebotene Kredit hat einen Zinssatz von 4% und eine Laufzeit von 4 Jahren. Welcher Kredit ist günstiger?"

    In diesem Beispiel schnappt man sich eine Programmiersprache, rotzt den Programmcode herunter und schaut sich das Ergebnis an.

    Hierunter könnte dein Programm fallen. Du möchtest Koperkonstruktor verstehen, also schreibst du ein Programm und schaust dir das Verhalten an.

    4.) Produktiver/professionieller EInsatz
    Im produktiven Einsatz versucht man Programme zu schreiben, welche möglichst wenig fehleranfällig, robust gegenüber Fehler (Eingabefehler), schnell, einfach, sauber, lesbar, dokumentiert, leicht erweiterbar, einfach zu bedienen,... ist.

    Und genau das ist der Unterschied zu den 3 vorherigen Richtungen. Auf einmal spielen Dinge wie fehleranfälligkeit eine Rolle.

    Betrachtet man dein Programm nun aus Sicht des produktiven Einsatzes, so stellt man sich halt die Frage warum du Pointer und Allokationen (new) nutzt. Beide Sachen erweisen sich nämlich als fehleranfällig.

    • Wer gibt beispielsweise den allokierten Speicher in int* coordinates; frei?
    • Warum erzwingt man hier ein new(), wenn man die Koordinaten doch direkt definieren kann ("int coordinates[2];")? Das macht das Programm doch unnötig langsamer.
    • Deine Funktion make_pair hat eine gewisse Ähnlichkeit zu std::make_pair. Deine Funktion kann aber im Gegensatz zu der std::make_pair Variante ein Speicherloch erzeugen. Nicht gut.

    usw.