Speicherzugriffsfehler bei Klassenpointer



  • Hallo,
    Ich versuche eine Klasse zu schreiben, mit der man mathematische Therme abspeichern kann. Dazu habe ich versucht, in die Klasse Zeiger auf sich selber zu speichern, um den rechten und linken Teil von Verknüpfungen jeweils im Therm zu speichern.
    Ich habe bis jetzt folgenden Code, der allerdings nicht funktioniert:

    #include <iostream>
    
    using namespace std;
    
    template <typename T = double>
    class Therm {
    private:
        Therm<T>* par;
    public:
        Therm<T> operator=(Therm<T>);
        Therm<T> operator+(Therm<T>);
        Therm();
        ~Therm();
    };
    
    template <typename T>
    Therm<T>::Therm() {
        par = NULL;
    }
    
    template <typename T>
    Therm<T>::~Therm() {
        delete[] par;
    }
    
    template <typename T>
    Therm<T> Therm<T>::operator=(Therm<T> val) {
        if (val.par != NULL) {
    	if (par == NULL) par = new Therm<T>[2];
    	par[0] = val.par[0];
    	par[1] = val.par[1];
        }
        return *this;
    }
    
    template <typename T>
    Therm<T> Therm<T>::operator+(Therm<T> val) {
        Therm<T> result;
        result.par = new Therm<T>[2];
        result.par[0] = *this;
        result.par[1] = val;
        return result;
    }
    
    int main() {
        Therm <>x, y;
        y=x+x;                   //funktioniert einwandfrei
        x+x+x;                   //führt zu einem Speicherzugriffsfehler
    }
    

    Was habe ich falsch gemacht?



  • zeiger schrieb:

    Was habe ich falsch gemacht?

    Die Regel der 3 nicht eingehalten.



  • Es heisst uebrigens Term, nicht Therm.



  • Was du da hast ist doch mehr oder weniger eine verkettete Liste?

    Ich glaube, dein Problem liegt unter anderem im Design. Sicher, dass du nicht einfach ein dynamisches Array mit Zeigern auf deine Objekte haben willst?



  • Sone schrieb:

    Was du da hast ist doch mehr oder weniger eine verkettete Liste?

    Das wird eher ein binärer Baum, wenn's mal groß ist.



  • manni66 schrieb:

    Die Regel der 3 nicht eingehalten.

    Die Regel der 3? Tut mir leid, die kenne ich nicht.

    Sone schrieb:

    Was du da hast ist doch mehr oder weniger eine verkettete Liste?

    Als verkettete Liste habe ich das auch schon probiert, indem ich Operatoren als Funktion auf einen bereits bestehenden Therm verstanden habe, das hat die selbe Fehlermeldung ausgelöst, zumal diese Lösung andere Probleme auslöst.

    Sone schrieb:

    Ich glaube, dein Problem liegt unter anderem im Design. Sicher, dass du nicht einfach ein dynamisches Array mit Zeigern auf deine Objekte haben willst?

    Ein dynamisches Array wollte ich haben, ja, habe ich auch. Aber einen dynamischen Array aus Zeigern? Ist das nicht komplizierter? Oder hat das gewisse Vorteile, die ich jetzt gerade nicht sehe?



  • Arrays können so gut wie alles beinhalten, und sonderlich kompliziert ist das auf keinen Fall.



  • Ich habe es gerade mal geändert, sodass Zeiger genutzt werden. Das sieht dann so aus:

    #include <iostream> 
    
    using namespace std; 
    
    template <typename T = double> 
    class Term { 
    private: 
         Term<T>** par;         //geaendert
    public: 
         Term<T> operator=(Term<T>); 
         Term<T> operator+(Term<T>); 
         Term(); 
         ~Term(); 
     }; 
    
    template <typename T> 
     Term<T>::Term() { 
         par = NULL; 
     } 
    
    template <typename T> 
     Term<T>::~Term() { 
         delete[] par; 
     } 
    
    template <typename T> 
     Term<T> Term<T>::operator=(Term<T> val) { 
         if (val.par != NULL) { 
         if (par == NULL) par = new Term<T>*[2]; 
         *par[0] = *val.par[0];         //geaendert
         *par[1] = *val.par[1];         //geaendert
         } 
         return *this; 
     } 
    
    template <typename T> 
     Term<T> Term<T>::operator+(Term<T> val) { 
         Term<T> result; 
         result.par = new Term<T>*[2]; 
         *result.par[0] = *this;      //geaendert
         *result.par[1] = val;        //geaendert
         return result; 
     } 
    
    int main() { 
         Term <>x, y; 
         y=x+x;                   //funktioniert einwandfrei 
         x+x+x;                   //führt zu einem Speicherzugriffsfehler 
     }
    

    Leider löst das immer noch den alten Fehler aus:
    <zahl> Speicherzugriffsfehler
    Was bedeutet das eigendlich?



  • zeiger schrieb:

    manni66 schrieb:

    Die Regel der 3 nicht eingehalten.

    Die Regel der 3? Tut mir leid, die kenne ich nicht.

    Die drei sind der Destruktor, der Kopierkonstruktor und der Zuweisungsoperator - und die Faustregel ist: brauchst Du einen brauchst Du alle.
    Also fehlt Dir noch der Kopierkonstruktor.

    Den operator+() nimmst Du raus und implementierst Ihn als freie Funktion. Und dann schaust Du Dir nochmal die Übergabe per Referenz an. Du übergibst quasi alles als value, was für viele temporäre Objekte sorgt und wahrscheinlich nicht das ist, was Du willst.
    Z.B. macht es keinen Sinn, dass der operator+() eine Kopie von *this zurückgibt.



  • Ok, vielen Dank jetzt klappt es, zumindestens gibt es jetzt keine Fehlermeldungen.
    Problem war tatsächlich der Kopierkonstruktor, denn der hat die pointer der Parameter in den Funktionen, die keine Referenzen waren, kopiert, sodass sie im Destrukor zwei mal gelöscht wurden.


Log in to reply