Problem beim Überladen von Operatoren



  • Moin,

    ich wollte mir mal eine Beispielklasse für Komplexe Zahlen bauen in der ich das Problem der überladenen Operatoren für spätere Implementierungen, sozusagen als Spicker einmal ideal löse. Leider bekomme ich das ganze nicht so richtig gebacken.

    Ich arbeite unter Kubuntu 13.04 mit der aktuellsten g++ Version, der Compiler Aufruf ist:
    g++ -Wall -O2 -o testProg main.cpp

    Die Klasse sieht im Moment aus wie folgt:

    class cmplx{
    
     public:
      cmplx(float a=0.0, float b=0.0){      
       r = new float;               
       i = new float;
       *r = a;                      
       *i = b;
      };
      ~cmplx(){                     
       delete r;    
       delete i;
      };
    
      float get_re() {return *r;};
      float get_im() {return *i;};
      void set_re(float a){*r = a;};
      void set_im(float a){*i = a;};
      void set_cmplx(float a,float b){
       *r = a;
       *i = b;
      };
      string get_cmplx(){
       stringstream buf;
       buf << *r << showpos << *i << "i";
       return buf.str();
      };
    
      cmplx& operator+=(cmplx& add){
       *r += add.get_re();
       *i += add.get_im();
       return *this;
      };
      cmplx operator+(cmplx& add){
       cmplx* dummy;
       dummy = new cmplx(0.0,0.0);
       return *dummy;
      };
     private:
      float* r;  
      float* i;
    };
    

    Wenn ich nun mit der Syntax z3=z2+z1 zwei komplexe Zahlen addieren will schmeißt er mir nen Backtrace:

    1+2i
    3+3i
    -1.56713e-15-1.56709e-15i
    *** Error in `./jOperator': double free or corruption (fasttop): 0x0000000000c340f0 ***
    ======= Backtrace: =========
    /lib/x86_64-linux-gnu/libc.so.6(+0x80a46)[0x7ff3a6adca46]
    ./jOperator[0x401d7c]
    ./jOperator[0x401a3b]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0x7ff3a6a7dea5]
    ./jOperator[0x401c51]
    

    Wie ihr seht hab ich alles was mit addieren zu tun hat schon aus der Operator Funktion rausgeschmissen und versuche sozusagen als Minimalbeispiel durch den "+"-Operator eine leere komplexe Zahl zurückzugeben. Und schon daran scheiter ich und ich habe keinen Schimmer warum 😕

    Hab schon alternative Implementierungen versucht(der einfachheit halber geb ich nur die modifizierten Codefetzen an):

    float get_re() const{return *r;};
      float get_im() const{return *i;};
    
      const cmplx operator+(const cmplx& add){
       cmplx* dummy;
       dummy = new cmplx(0.0,0.0);
       return *dummy;
      };
    
    cmplx operator+(cmplx& add){
       cmplx dummy(0.0,0.0);
       return dummy;
      };
    

    Irgendwie gehen mir die Ideen und die Stellen an denen ich nachschlagen kann aus vielleicht kann mir hier jemand sagen wo mein Denkfehler liegt. Cool wäre auch ne "verständliche" Erklärung warum es auf diese und keine andere Weise funktioniert.

    Danke im voraus.
    MfG Illo



  • Hast du schonmal von der "Regel der großen Drei" gehört? Es scheitert daran, dass du keinen Zuweisungsoperator und Kopierkonstruktor definiert hast.

    Außerdem ist das viele new absolut unangebracht. Das geht hier alles ohne dynamisch erzeugte Objekte:

    class cmplx {
      float re, im;
      // ...
    }
    

    (Dann hast du das obige Problem automatisch nicht.)



  • Ich hätte vielleicht dazusagen sollen, dass ich ein Beispielprogramm für nicht dynamisch alloziierte Variablen schon habe, das funktioniert auch sehr gut. Ich wollte es in diesem Beispiel allerdings explizit für dynamisch alloziierte Bereiche machen.

    Was ist die Regel der großen drei, und wie hilft mir ein Copy-Konstruktor ?

    mfg Illo


  • Mod

    Illoran schrieb:

    Was ist die Regel der großen drei, und wie hilft mir ein Copy-Konstruktor ?

    Was macht man, wenn man ein Stichwort erhalten hat und nicht weiß, was es bedeutet?



  • SeppJ schrieb:

    Illoran schrieb:

    Was ist die Regel der großen drei, und wie hilft mir ein Copy-Konstruktor ?

    Was macht man, wenn man ein Stichwort erhalten hat und nicht weiß, was es bedeutet?

    Ja sry 🙂 ... bin grade parallel schon dabei die Google Hits abzuarbeiten :p

    mfg Illo



  • Ich sehe viel zu viel new und Zeiger und überhaupt gar kein delete. Du verletzt die Dreierregel und hast ein Speicherleck in operator+. Es wurde so oder so ähnlich zwar schon gesagt, aber ich sage es nochmal, um die Wichtigkeit/Ernsthaftigkeit zu unterstreichen: Das Design ist eine extrem schlechte Idee. Ja, es ist nur ein Beispiel, aber auch in der Praxis würde man so etwas so gut wie nie machen. Deine Klasse muss hier gleich zwei Ressourcen manuell verwalten. Das ist mindestens eine zu viel, da sehr fehleranfällig.



  • Hmm ... mir fehlt da tatsächlich etwas die Erfahrung, wie wäre das Design denn eine gute Idee ? Sollte man tatsächlich weitesgehend auf dynamische Alloziierung verzichten und das ganze Ding ohne Pointer bauen, oder gibt es Praxisnahe Anwendungen für das grundsätzliche Konzept der Klasse und meine Implementierung ist einfach Schrott ?

    mfg Illo



  • Kein new/delete benutzen. Ausgabe per überladenem friend Operator <<. Binäre arithmetische und Vergleichsoperatoren auch als friend (außerhalb). Keine Setter, sondern nur Konstruktoren.


Anmelden zum Antworten