Probleme mit delete und Destruktor



  • Moin,

    ich habe eine Klasse geschrieben, in der es dynamisch allokierte Objekte gibt,

    das ganze so wie ichs hier gepostet dient bis jetzt dazu die Determinanante von

    einer beliebigen nxn Matrix ausrechnen.

    Die memberfunktion "matrix matrix::solvenxn()" tut dies rekursiv.

    Das ganze lief bis ich im Destruktor den "delete " Befehl eingesetzt habe,

    dann gings nimmer.

    Ich hab gegoogelt aber die Infos haben mich nicht weitergebracht, darum frage

    ich hier.

    (Vielen Dank schonmal im Voraus)

    Der Code:

    Die header Datei mit der Klasse:

    #ifndef head_h
    #define head_h
    
    using namespace std;
    
    class matrix{
          float **element;
          const unsigned short int n,m;
    
    public:
    
    matrix():n(1),m(1){
             element=new float*[1];
             element[0]=new float [1];
             element[0][0]=0.f;           
    }// matrix()
    
    ~matrix(){                        //hier gibts Probleme
          delete[] element;}
    }//destruktor
    
    matrix(int rows,int columns,char *a):n( rows),m( columns){
    
           element=new float*[rows];
           for (int ii=0;ii<columns;ii++) element[ii]=new float [columns];
    
           switch( *a){ 
    
           case 'c':
           for (int ii=0;ii<n;ii++){
           for (int jj=0;jj<m;jj++){
           cin>>element[ii][jj];
           }//for jj
           }//for ii
           break;
    
           case 'r':
           for (int ii=0;ii<n;ii++){
           for (int jj=0;jj<m;jj++){
           element[ii][jj]=rand()%10;
           }//for jj
           }//for ii
           break;
           case 'i':
           for (int ii=0;ii<n;ii++){
           for (int jj=0;jj<m;jj++){
           element[ii][jj]=(ii!=jj) ? 0.f:1;
           }//for jj
           }//for ii
    
           break;
    
           }//switch a
    }//matrix(const int &rows, const int &columns,char *a)
    
    matrix(int rows,  int columns):n( rows),m( columns){
           element=new float*[rows];
           for (int ii=0;ii<columns;ii++) element[ii]=new float [columns];
    }//matrix(const int &rows, const int &columns)
    
    void matrix::tellme(){
         cout<<endl;
         for(int ii=0;ii<n;ii++){
         for(int jj=0;jj<m;jj++){
         cout<<element[ii][jj]<<"   ";
         }//for jj
         cout<<endl;
         }//for jj
         cout<<endl;
    }//tellme()
    
    matrix matrix::choice(int row){
           matrix c(n-1,m-1);
           int kk=0;
    
           for(int ii=0;ii<n;ii++){
           if(ii==row){continue;}
           for(int jj=1;jj<n;jj++){
           c.element[kk][jj-1]=element[ii][jj];
           }//for jj
           kk++;
           }//for ii
    
           return c;
    }// choice
    
    matrix matrix::solve3x3()const{
          matrix result;
          if(element[0][0]!=0){result.element[0][0]=element[0][0]*(element[1][1]*element[2][2]-element[2][1]*element[1][2]);} 
          if(element[1][0]!=0){result.element[0][0] +=  -element[1][0]*(element[0][1]*element[2][2]-element[2][1]*element[0][2]);}
          if(element[2][0]!=0){result.element[0][0] +=element[2][0]*(element[0][1]*element[1][2]-element[1][1]*element[0][2]);}
          return result;
    }//solve 3x3
    
    matrix matrix::solvenxn(){
          matrix c;
          float v=1;
    
          if(n!=m){cout<<"Das geht doch garnicht "<<endl;return c;} 
    
          else if(n<3){
          c.element[0][0]=(n!=1)? element[0][0]*element[1][1]-element[1][0]*element[0][1]:element[0][0];
          }// if(n<3)
          else if (n>3){        
          for (int ii=0;ii<n;ii++){
          ((ii%2)==0)?v=1:v=-1;
          if(element[ii][0]!=0){ c.element[0][0]+=v*element[ii][0]*(choice(ii).solvenxn()).element[0][0];}
          else{ continue;}
          }//for ii
          }//if (n>3)
          else{return solve3x3();}//else if (n>3)
    
          return c;
    }//solve nxn
    
    };//class matrix
    
    #endif
    

    Die Main Datei:

    #include<iostream>
    #include "head.h"
    #include<time.h>
    using namespace std;
    
        int main(){
        time_t t;
        time(&t);
        srand((unsigned int)t);
    
        matrix c(5,5,"r");              //erstellt eine random 5 x 5 matrix
        c.tellme();                     // gibt sie aus
        (c.solvenxn()).tellme();        //und könnte ohne den Fehler mit dem
                                        //delete auch die Determinante berechnen
    
        system("Pause");
        return 0;
        }//main
    


  • Ohne deinen Code angeguckt zu haben:

    dann gings nimmer.

    Bitte beschreibe, was nicht mehr geht und wie es nicht mehr geht!
    Exceptions? Kompiler / Linker Error?



  • Nimm doch std::vector, dann funktionierts, wette ich.


  • Mod

    Was geht nicht?

    Dein Code hat lauter Klammern falsch, dürfte gar nicht compilieren. Du verletzt die Regel der großen Drei, was immer wieder für lustige Probleme sorgt, wenn man mit Pointern hantiert.

    Dein Code hat auch noch andere Schwächen, da er jedoch ziemlich unleserlich ist, mag ich nicht im Detail da drauf eingehen.



  • Kompiliert wird es, es erscheint dann beim Programmablauf eine Fehlermeldung

    das det.exe ein Problem festgestellt hat.



  • Itrah schrieb:

    Kompiliert wird es, es erscheint dann beim Programmablauf eine Fehlermeldung

    das det.exe ein Problem festgestellt hat.

    Dann hilft typischerweise mit Debugger durchzusteppen, d.h. jede einzelne Anweisung nacheinander Ausführen und die Variabeln beobachten.

    Was für eine IDE benutzt Du?



  • Ich nutze dev c++ version 4.9.9.2

    Also durchstepen habe ich schon probiert, und hab festgetellt das es bei

    der Rekursion wohl mit den Rückgabewerten nicht mehr klappt.

    Allerdings kann ich mir das im zusammenhang mit dem delete nicht erklären.



  • Itrah schrieb:

    Ich nutze dev c++ version 4.9.9.2

    Ich empfehle dringend zu wechseln. Zudem bitte nicht in Sätzen mit Return umbrechen (das macht das Forum selbstständig am Rand, und ist zudem besser lesbar).

    Grundsätzlich: Wer mit Zeigern in Klassen hantiert benötigt neben dem Konstruktor auch den Kopierkonstruktor und Zuweisungsoperator (Die Bereits erwähnte Regel der Drei).

    Zudem ist der Code so unleserlich formatiert, das die meisten wohl kaum den Code lesen werden.



  • Laut Wikpedia ist die neuste Version von Dev C++ von letztem Monat. Keine Ahnung, inwieweit das stimmt und ob es aktuell ist.



  • Wikipedia schrieb:

    Nachdem sich in der Entwicklung von Dev-C++ seit März 2005 nichts getan hatte, erschien am 30. Juni 2011 eine neue Version (4.9.9.3) von Dev-C++, der kurz darauf Version 4.9.9.4 folgte. Diese beiden Versionen enthalten mit Version 4.5.2 ein neue Version des GCC und bringen auch alle erforderlichen Ressourcen zum Programmieren von DirectX und Win32 mit. Viele Bugs und Stabilitätsprobleme wurden ebenso behoben.

    Da scheint sich was zum positiven zu wenden 🙂


  • Mod

    Also wenn ich mal die zahlreichen Syntaxfehler (überflüssige Qualifikationen bei Membern, fehlerhafte Includes, fehlerhafte Klammerung) korrigiere, so dass der Code überhaupt compiliert, kann man das auch debuggen. Wie schon gesagt, verletzt du die großen drei. Weiterhin liest du fröhlich über alle Arraygrenzen hinaus und ach, es ist einfach nur Chaos. Nicht einmal mit dem Debugger finde ich da richtig durch, da alle Variablen nur kryptische einbuchstabige Namen haben.

    Mein Wischiwaschi-Tipp: Befolge die großen Drei. Oder einfacher, machs wie von Pi vorgeschlagen und nimm einen vector. Dann machst du alle Zugriffe mit at(), damit du die Zugriffsfehler alle findest und korrigieren kannst. Vielleicht funktioniert es dann schon.

    Mein Hardcore-Tipp: Alles nochmal neu machen. Und dieses Mal sauber!

    Main Praxis-Tipp: Du bist nicht der erste, der mit Matrizen rechnet 🙂 . Da gibt es tausende Bibliotheken für und alle sind sie besser als deine.



  • Zunächst mal danke ich allen die geantwortet haben.

    Egal wie ungeschickt oder wirr mein Code ist, es muss ja irgendwas mit dem delete

    Befehl zu tun haben denn ohne läufts und die Ergebnisse stimmen.

    Meine Frage währe nun:

    Wie würde man, wen man wie ich hier in einer Klasse mit new Member erstellt die

    freigabe korrekt regeln?



  • Halte dich doch an die Tipps von SeppJ. std::vector könnte dir eine Menge Arbeit abnehmen, wenn du deine Matrizen unbedingt selbst schreiben möchtest. Aber ich würde deinen Code auf jeden Fall neu machen, du kannst ihn doch selbst auch kaum lesen, hab ich Recht? 😉



  • Ja ich will die Matritzen selber machen, sonst weis ich ja hinterher nicht

    wie ich das mit der freigabe in Zukunft regele.


  • Mod

    Itrah schrieb:

    Wie würde man, wen man wie ich hier in einer Klasse mit new Member erstellt die

    freigabe korrekt regeln?

    Schon so wie du es gerade anfängst, aber eben mit allem drum und dran. Ich, asc und andere haben dir schon gesagt, was fehlt und was falsch läuft. Wenn du das nicht verstehst, google es oder frag genauer nach. Jedenfalls solltest du dich solange nicht wundern, dass dein Programm solche Fehler verursacht, wie du entweder nur den Destruktor implementiert hast oder nicht fertige Rundum-Glücklich-Klassen wie vector benutzt.

    P.S.: Und bitte lass im Forum den manuellen Zeilenumbruch sein. Wir haben zuhause alle eine andere Bildschirmauflösung wie du, dafür aber hochentwickelte Programme namens Browser, die uns den Text passend umbrechen.



  • Itrah schrieb:

    Egal wie ungeschickt oder wirr mein Code ist, es muss ja irgendwas mit dem delete Befehl zu tun haben denn ohne läufts und die Ergebnisse stimmen.

    An delete liegt es nicht, zumindest nicht direkt. Du rufst mehrfach auf dem gleichen Speicherbereich delete auf (Dank fehlenden Kopierkonstruktor usw.).

    Stell dir folgendes vor:

    class A {};
    
    int main()
    {
      A a;
      A b(a); // Kopierkonstruktor.
      A c;
      c = a; // Zuweisungsoperator.
    }
    

    Bei jeder einfachen Klasse ist obiger Code unproblematisch, da hier einfach Werte kopiert werden. Am Schluß von main wird der Destruktor von a,b und c aufgerufen.

    Nun ergänzen wir das ganze mal:

    class A
    {
      private:
        int * p;
    
      public:
        A() : p(new int(1)) {}
        ~A() { delete p; }
    };
    
    int main()
    {
      A a;    // Legt a.p per new an.
      A b(a); // Kopiert den Zeiger von a.p nach b.p
      A c;    // Legt c.p per new an.
      c = a;  // Überschreibt c.p mit a.p
    } // Destruktor von a,b,c versuchen jeweils a.p freizugeben (=>Fehler), zudem
      // Speicherleck bei der zweiten per new allozierten Variable, da kein new
      // aufgerufen wird.
    

    Hier fehlen ein eigener Kopierkonstruktor und Zuweisungsoperator...

    class A
    {
      private:
        int * p;
    
      public:
        A()
        : p(new int(1))
        {
        }
    
        A(
          A const & rhs)
        : p(new int(*rhs.p)) // Nicht Zeiger kopieren, sondern "Inhalt" in einem
        {                    // neu allozierten Speicherbereich kopieren.
        }
    
        A & operator=(
          A const & rhs)
        {
          // Es existiert bereits ein Speicherbereich p.
          // Ich werde nun die nicht ganz saubere (aber für den Anfang
          // verständlichere) Variante beschränken:
    
          delete p; // Alten Speicherbereich löschen
          p = new int(*rhs.p); // Wie beim Kopierkonstruktor nicht den Zeiger,
                               // sondern den "Inhalt" in einen neu allozierten
                               // Speicherbereich kopieren.
          return *this;
        }
    
        ~A()
        {
          delete p;
        }
    };
    
    int main()
    {
      A a;    // Legt a.p per new an.
      A b(a); // Kopiert den Inhalt, auf den der Zeiger a.p verweist in einen
              //  neuen Speicherbereich (b.p)
      A c;    // Legt c.p per new an.
      c = a;  // c.p wird gelöscht, Inhalt auf dem der Zeiger a.p verweist wird
              //  in den neuen Speicherbereich (c.p) abgelegt.
    } // Die Destruktoren löschen alle ihre "eigenen" Speicherbereiche.
    

    P.S: Viele Aufrufe von Konstruktoren/Kopierkonstruktoren und Zuweisungen "sieht" man erst wenn man etwas länger C++ programmiert hat, und selbst dann kann man gerne einige übersehen.



  • Klar das es nicht gehen kann, aber so hatte ichs nicht betrachtet.

    Vielen Dank.


Anmelden zum Antworten