Probleme mit dem Destructor



  • Hi,

    ich bin aus dem ganzen OOP-Spass leider schon etwas raus und dachte mir, naja... vielleicht wäre ein kleines Projekt zur Übung ganz nett.

    Eigentlich sollte es ganz einfach sein ^^ ...

    Ich habe ein kleines Programm geschrieben, welches kleine Datensätze in einer Klasse namens node anlegt und mehrere davon in einer Klasse namens stacks ablegt und dort dann ggf weiterverarbeiten kann.

    ich habe hierzu einen Datentyp via typedef angelegt, welcher ein Zeiger auf einen node ist und knot heißt.

    Allerdings überfordert mich gerade diese Zeiger-Meyerei etwas, denn, da alles auf Zeigern basiert und ich node-Objekte dynamisch mit new anlege, muss ich die im Destructor auch wieder loswerden.

    Ich habe eine add() Methode in stacks geschieben, die weitere knot-Objekte hinzufügen kann und dafür auch Platz schafft. Das klappt soweit, allerdings... sobald der Platzhalter-stacks b (dachte das sei eine gute Idee beim Kopieren) an seinen Destructor kommt haut es mir (logisch!) die Objekte weg, auf welche die Zeiger in b gezeigt haben.

    Jetzt weiß ich nicht, wie ich das so hindrehe, dass das erstens nicht passiert, zweitens ich keine Speicherlecks hinterlasse, kommentiere ich den Stacks destructor aus geht natürlich alles, allerdings werden meine node-Objekte auch nicht gelöscht.

    stacks::~stacks(){
        for (int i = 0; i < this->parts; i++){
            delete this->a[i];
        }
    
        cout << "auch weg" << endl;
    }
    
    
    void stacks::add(knot neu){
        if(this->a[this->parts] != 0){
            stacks b(this->parts);
    
            for(int i = 0; i < this->parts; i++){
                b.a[i] = this->a[i];
            }
    
            this->a = new knot[this->parts+1];
    
            for(int i = 0; i < this->parts; i++){
                this->a[i] = b.a[i];
            }
        }
        this->a[this->parts] = neu;
        parts++;
    }
    

    Ich weiß, das wirkt sicher wie eine Schulaufgabe, ist es aber nicht, trotz des harten Dilletantismus.

    Ich würde mich sehr freuen, wenn mir jemand auf den richtigen Weg helfen könnte, ich habe das blöde Gefühl, dass ich eigentlich wissen sollte, wie man das löst, komme aber einfach nicht drauf.



  • Wenn du C++ lernen willst, kauf dir ein anständiges C++ Buch.



  • Nur als Hinweis. Du erzeugst ein Array mit new[] also solltest du auch ein Array löschen und nicht dessen einzelne Elemente. Hier ist aber noch mehr im Argen.



  • Ich dachte, falls ich allerdings das Array lösche bevor ich seinen Inhalt lösche, den ich ebenfalls mit new anlege... dann werden doch die node-Elemente (knot ist ein Zeiger auf node) nicht gelöscht, ich sehe in der Ausgabe jedenfalls keine Aufrufe des node-Destructors, wenn ich das tue.

    Aber ich hab das noch hinzugefügt, stimmt schon, dass das fehlt.

    Das ganze Programm ist mittlerweile, vermutlich gepfuscht aber zumindest lauffähig. Ich überschreibe die Zeiger in b einfach mit nullen, dann werden nicht die tatsächlichen nodes gelöscht.

    
    void stacks::add(knot neu){
        if(this->a[this->parts] != 0){
            stacks b(this->parts);
    
            for(int i = 0; i < this->parts; i++){
                b.a[i] = this->a[i];
            }
            delete [] this->a;
            this->a = new knot[this->parts+1];
    
            for(int i = 0; i < this->parts; i++){
                this->a[i] = b.a[i];
                b.a[i] = 0;
            }
        }
        this->a[this->parts] = neu;
        parts++;
    }
    


  • @protagonist
    Preisfrage: Was passiert mit Deinen Knoten, wenn die lokale Variable b gelöscht wird?



  • @mgaeckler ich denke nichts.

    Bedeutet das es wäre erheblich geschickter, wenn ich anstatt b (ein "stacks") b ein Array auf knot sein lasse? so würde die lokale variable gelöscht werdne aber der inhalt bleibt ganz ohne gehampel stehen.



  • Die Frage ist, was willst Du mit dieser Klasse überhaupt erreichen. Sprich willst Du händische Speicherverwaltung lernen, oder soll diese Klasse effektiv für etwas benutzt werden. Falls es das erste ist, ist das ok und dann solltest Du die Fehler auch alle eliminieren. Falls nicht dann schreibt man die Klasse komplett anders bzw. weshalb wird nicht gleich so etwas wie std::vector genutzt?



  • @john-0 Nein, es ist ersteres, es geht rein um das Machen, ich benutze das für nichts.



  • Wie immer bei solchen Fällen ist ein minimales compilierbares Beispiel sehr sinnvoll. Sprich alle Teile die mit der Speicherverwaltung der Klasse stacks zu tun haben, sollten enthalten sein. D.h. vor allem die Definition der Klasse. Der Destruktor kann z.B. auch nicht korrekt sein, da Du ein Array verwendets und das nicht freigibst.



  • @john-0 klar, kann ich machen.

    main()

    #include <iostream>
    #include "node.hpp"
    #include "stack.hpp"
    
    using namespace std;
    
    int main()
    {
        stacks x;
        
        x.add();
        x.add();
        x.add();
        x.add();
    
        x.nameout();
    
        return 0;
    }
    
    

    node.hpp

    #ifndef NODE_HPP_INCLUDED
    #define NODE_HPP_INCLUDED
    #include <string>
    
    using namespace std;
    
    class node {
       private:
            string name;
         
        public:
            node();
            ~node();
    
            void setname(string);
            string getname();
    };
    
    typedef node *knot;
    
    #endif // NODE_HPP_INCLUDED
    

    node.cpp

    #include <iostream>
    #include <string>
    #include "node.hpp"
    
    using namespace std;
    
    node::node(){
        name = "-";
    }
    
    node::~node(){
        cout << "weg" << endl;
    }
    
    void node::setname(string name){
        this->name = name;
    }
    
    string node::getname(){
        return this->name;
    }
    

    stack.hpp

    #ifndef STACK_HPP_INCLUDED
    #define STACK_HPP_INCLUDED
    
    #include "node.hpp"
    #include <string>
    
    using namespace std;
    
    class stacks{
        private:
            int parts;
            knot *a;
    
        public:
            stacks();
            ~stacks();
    
            void add();
            void nameout();
    };
    
    #endif // STACK_HPP_INCLUDED
    

    stack.cpp

    #include "stack.hpp"
    #include <iostream>
    
    using namespace std;
    
    stacks::stacks(){
        parts = 0;
        a = new knot[1];
    
        for (int i = 0; i < 1; i++){
            a[i] = 0;
        }
    }
    
    stacks::~stacks(){
        for (int i = 0; i < this->parts; i++){
            delete this->a[i];
        }
        delete[] a;
    
        cout << "auch weg" << endl;
    }
    
    
    void stacks::add(){
        if(this->a[this->parts] != 0){
            knot b[this->parts];
    
            for(int i = 0; i < this->parts; i++){
                b[i] = this->a[i];
            }
            delete [] this->a;
            this->a = new knot[this->parts+1];
    
            for(int i = 0; i < this->parts; i++){
                this->a[i] = b[i];
            }
        }
    
        this->a[this->parts] = new node;
        parts++;
    }
    
    void stacks::nameout(){
        for (int i = 0; i < parts; i++)
            cout << a[i]->getname() << endl;
    }
    

    das ist der aktuelle Stand und scheint zu laufen.


Log in to reply