Problem beim freigeben rekursiv aufgebauter Struktur



  • Moin

    edit 30.5. 3.15 Uhr: Das Problem mit dem absturz ist gelöst, hab meine blödheit im code mal fett markiert -.- schlimm wenn man sowas bestimmt 30 mal überliest. jetzt bleibt nur noch ein kleines speicherleck, wenn das auch wech ist markier ich es dann auch als gelöst. Danke an alle hilfreichen Seelen.

    Ich versuche grade einen Planetengenerator zu schreiben der die Topographische Grobstruktur des Planeten ausnahmsweise mal nicht über einen Fraktalgenerator laufen lässt.
    Als Grundlage dafür muss ich den Planeten mit einem Gitternetz überziehen. Idealeweise sollten die Pnkte ja annähernd gleichverteilt sein.
    Nach vielen Stunden Mathemagie bin ich zu dem Schluss gekommen es aus einem Ikosaedernetz zu entwickeln.
    Aus Speicher- und auch Leistungsgründen werden nur die Interessanten bereicher feiner Unterteilt werden soll.

    Mein dafür geschriebenes Strukturengewirr erzeugt mir sobald ich den Speicher über den Destruktor freigebe oder auch wenn ich ihn am Programmende automatisch freigeben lasse eine Speicherbereichsüberschreitung und es stürzt mit Fehlermeldung 0xC0000005 ab.

    Ich finde den fehler nun nur leider nicht, oder muss/sollte ich das anders lösen?
    Meine vermutung ist ja das ich beim anfordern/ freigeben einen falschen befehl verwendet habe aber meine literatur und die allessehende Suchmaschiene haben mich auf nichts aufmerksam gemacht.

    wäre nett wenn ihr mir weiterhelfen könntet.
    gruß Darki

    hier mal das Strukturgewirr

    // Speicherindex für alle benötigten werte jedes Punktes auf dem Globus
    struct Punktwerte{
        int x;
        int y;
        int z;
        int h;
    };
    
    // Bei Bedarf zu erzeugendes feines Gitter
    struct Feinnetzindex{
    Punktwerte Punktwerteindex[Subteilung+1][Subteilung+1];
    };
    
    // Bei Bedarf zu erzeugendes genaueres Gitter
    struct Subnetzindex{
    Feinnetzindex *feinnetz[Subteilung+1][Subteilung+1];
    Punktwerte Punktwerteindex[Subteilung+1][Subteilung+1];
    };
    
    // In kleinere Stücke aufgeteilts Ikosaedernetzquadrat.
    struct netzhauptindex{
    Subnetzindex *subnetz[Teilung+1][Teilung+1];
    Punktwerte Punktwerteindex[Teilung+1][Teilung+1];
    };
    
    // In Quadrate Unterteiltes Ikosaedernetz
    struct Topnetzindex{
    netzhauptindex *hauptnetz[[b]10[/b]];
    };
    
    class Planetennetz{
        public:
    
            Planetennetz();  
            ~Planetennetz();  
    
        private;
            // Zeiger auf das in Quadrate unterteilte Ikosaedernetz
            Topnetzindex *topnetz;  
    
    };
    

    der Konstuktor und der Destruktor

    //Erzeugt ein unterteiltes Ikosaedernet beim Aufruf
    Planetennetz::Planetennetz(){
        topnetz = new Topnetzindex;
        for(int i = 0;i<[b]10[/b];i++){
            (*topnetz).hauptnetz[i]=new netzhauptindex;
            for (int j=0; j < Teilung +1; j++){
            for (int k=0; k < Teilung +1; k++){
            (*(*topnetz).hauptnetz[i]).subnetz[j][k]=NULL;
            }
            }
        }
    }
    // soll prüfen ob speicher bereitgestellt wurde. Wenn ja soll es ihn freigeben.
    Planetennetz::~Planetennetz(){
      if (topnetz != NULL){
        for(int i=0; i<[b]20[/b];i++){
        if((*topnetz).hauptnetz[i] != NULL){
            for (int j=0; j < Teilung +1; j++){
            for (int k=0; k < Teilung +1; k++){
            if( (*(*topnetz).hauptnetz[i]).subnetz[j][k] != NULL){
                for (int l=0; l < Subteilung +1; l++){
                for (int m=0; m < Subteilung +1; m++){
                    if( (*(*(*topnetz).hauptnetz[i]).subnetz[j][k]).feinnetz[l][m] != NULL){
                    delete (*(*(*topnetz).hauptnetz[i]).subnetz[j][k]).feinnetz[l][m];
                    }
                }
                }
            delete (*(*topnetz).hauptnetz[i]).subnetz[j][k];
            }
            }
            }
        delete (*topnetz).hauptnetz[i];
        }
        }
    
      delete topnetz;
      }
    }
    

  • Mod

    Google mal RAII und Smartpointer, insbesondere unique_ptr/auto_ptr. Beides (eigentlich ist das eine nur eine mögliche Umsetzung des anderen) ist bei deiner Struktur keine große Änderung und löst mit einem Schlag alle Probleme. Und du solltest das sowieso immer so machen (beides, also RAII oder die fertigen Klassen aus der Standardbibliothek benutzen), nicht nur in diesem Programm.



  • Vernetzte Struktur und Verwaltung des Speichers entkoppeln. D.h. deine Knoten koennen wild mit Zeigern aufeinander verweisen. Werden sie in einer seperaten Liste nochmals aufgelistet, koennen sie einzeln ohne Rekursion wieder freigegeben werden. Smartpointer werden dir auch nicht helfen, Ordnung in das Chaos zu bringen.



  • Erstmal danke euch beiden.

    Wenn man die fertigen Klassen schon kennt macht man das wenn man keine besonderen Gründe hat sie nicht zu nutzen, nimmt man sie doch immer gern 🙂
    Muss mich noch ganz gut in der Sache weiterbilden. Das ich die nicht verwendet bekomme.

    Hab mich jetzt mal grob in die smartpointer eingelesen. Muss ich morgen mal testen ob es dann immer noch abstürzt. Für mich stellt sich nur die Frage. Wo der nachteil der Smartpointer liegt, Geschwindigkeit sollte es nicht sein. Aber kann es sein das ein Smartpointer mehr Speicheraufwand bedeutet als ein normaler?

    Das mit der liste habe ich nur noch nicht ganz durchdrungen wie die Lösung dort ausehen würde. Weil wenn ich in meiner struktur jedem Feld ein punkt in einer liste zuordnen muss um dort den Zeiger auszulesen, warum parke ich den dann nicht gleich dort wo ich den eintrag für die Liste hingepackt hätte 😕 ?
    Aber hat diese lösung nicht auch gut viel zusätzlichen speicherbedarf in dieser anwendung.

    War im allgemeinen am grübeln ob ich wegen der vielen punkte um den Globus nicht sowiso einen recht guten Speicherbedarf habe, der sobald ich genauere Gitternetzte anfordere nicht sogar recht enorm wird.

    Aber ich teste erstmal ob es damit tut und das mit der größe kann ich danach ja nochmal nachrechnen/ausprobieren.


  • Mod

    Ein shared_pointer (also ein Referenzen zählender Pointer) hat Mehraufwand und ist tatsächlich ein bisschen fetter und langsamer (nicht beim Zugriff, aber Löschen, Erstellen und Kopieren sind aufwändiger). Ein auto_ptr/unique_ptr ist ein normaler Pointer mit Zuckerguss und hat diesem gegenüber keine Nachteile, außer, dass man damit nur machen kann, wofür es vorgesehen ist, also keine Referenzübergabe oder nicht besitzende Verhältnisse ausdrücken und erst recht keine dreckigen Pointerhacks.

    Sehr ähnlich verhalt es sich mit fast allen anderen Klassen aus der Standardbibliothek. Sie haben 0 Overhead gegenüber händischem Pointergefummel* (man darf sogar davon ausgehen, sie sind wesentlich besser als ein einzelner Programmierer es an einem Nachmittag programmieren könnte), aber sie lassen sich nicht zu irgendwelchem Unsinn missbrauchen. Außerdem kommen sie strukturbedingt meistens mit optionaler Debugfunktionalität (mal im Handbuch des Compilers gucken) die man bei Bedarf einschalten kann. Bei selbst gebauten Strukturen ist dies so gut wie unmöglich, sofern man nicht die Schnittstellen der Standardbibliothek nachbaut.

    *: Zumindest, wenn man es richtig macht. Man kann sicherlich irgendwelchen Code mit riesigen Problemen schreiben, der das gleiche Ergebnis hat und ein bisschen schneller ist.


Anmelden zum Antworten