Memory Leak bei STD::Map



  • Hymir90 schrieb:

    ich sollte also noch ne copy operator und nen operator= schreiben und das sollte das problem lösen?
    =O

    Ne, das glaube ich nicht. Aber hier stellen sich so viele Fragen, z.B. wieso dynamische Speicherverwaltung mit new, wieso rohe Zeiger, wieso reinterpreter-Casts, wieso dynamische Arrays mit new[], wieso ist der Value der map ein roher Zeiger, wieso kommt da nirgendwo const vor 😕 Fragen über Frange. All das zusammen führt zu deinen Bugs.



  • stringutils.hh

    1. warum .hh als Endung? Ist eher ungewöhnlich. .h oder .hpp, seltener .hxx
    2. warum benutzt du <string.h>? (Der C++-Header hieße <cstring>, wenn du die C-String Funktionen brauchst)
    3. using namespace std auf namespace-Ebene in einem header - vielleicht keine gute Idee
    4. wozu das temporäre char-array str in der Funktion? den hash kannst du genauso auf dem übergebene array berechnen.
    5. warum char* als Parameter und nicht char const*, wenn du das übergebene char-Array nicht änderst?
    6. warum eine statische Variable hash und als Rückgabe eine Referenz darauf???? 😕 Das schreit nach verrücktem, unerwarteten Verhalten
    7. wozu <iostream>, <sstream> und <string> einbinden, wenn du sie nicht nutzt?
    8. warum ist die Funktion nicht inline definiert? Damit hast du eine ODR-Verletzung, sobald du den header in mehr als einer Übersetzungseinheit einbindest.

    hashmap.hh
    9) Warum wirfst du überall mit Pointern um dich? Das sieht schonmal arg nach Java-Abkömmling aus, und da wundert es nicht mehr, warum du überall memleaks hast. Zumal du dann bei den Gettern von MapElement plötzlich Kopien zurück gibst, was wiederum absolut unnötig ist.
    10) MapElement übernimmt offenbar den Besitz von filename und path (löscht sie zumindest im DTor). Da du aber keinen op= und keinen Copy-Ctor erstellt hast, läufst du wenn du das Ding an eine std::map übergibst schneller auf double deletes als du "huch" sagen kannst.

    Da gibts noch viele weitere Punkte, aber nach der Pointerschlacht hab ich aufgegeben, weiter zu schauen. Mein Fazit: Dass du memleaks hast, ist nicht verwunderlich. Verwunderlich ist eher, dass Programm soweit durchläuft, dass valgrind dir irgendwas sagen kann, bevor dir das ganze Ding um die Ohren fliegt. Ich empfehle dringend, dich vom Referenz-Denken aus Java (oder C# oder woher auch immer du das hast) zu lösen und mit einem guten C++-Buch die Grundlagen zu erarbeiten.



  • jawohl jawohl, ich gebs ja zu! ^^ Ich komm aus der Java-Ecke und hab grad echte Probleme mit den Pointern usw. Danke erstmal für die vielen Antworten. Ich werde mir das mal in Ruhe anschauen!

    MfG


  • Mod

    Man sollte mal erwähnen, dass die ganze Prämisse bezüglich einer fehlenden Hashmap falsch ist:
    http://en.wikipedia.org/wiki/Unordered_associative_containers_(C%2B%2B)#History



  • Mal abgesehen hat C++ bereits eine Hashmap. std::unordered_map.

    Edit: Ach Mist, zu langsam 😞



  • Hymir90 schrieb:

    jawohl jawohl, ich gebs ja zu! ^^ Ich komm aus der Java-Ecke und hab grad echte Probleme mit den Pointern usw. Danke erstmal für die vielen Antworten. Ich werde mir das mal in Ruhe anschauen!

    Das macht aber gar nichts. Zeiger brauchst du in C++ nur selten. Deswegen kannst du Zeiger erstmal aus deinem Kopf streichen. 😉



  • In Boost und der C++11-Bibliothek gibts übrigens eine unordered_map, dürfte in deine Richtung gehen 😉

    Wie deine Hashfunktion aussehen könnte:

    #ifndef stringutils_hpp
    #define stringutils_hpp
    
    namespace stringutils{
      /**
         hashSDBM
         wandelt char* in Hashwert (SDBM - Algorithmus)
         @param strToHash            zu hashender String
         @return Hashwert
      */
      unsigned long hashSDBM(char const* strToHash){
        unsigned long hash = 0;
        for(;*strToHash;++strToHash)
          hash = *strToHash + (hash <<6) + (hash <<16) - hash;
        return hash;
        }
    
    #endif
    

    Wobei ich nicht sicher bin, ob das so klug ist, char* als Parameter zu haben, wenn hash ein unsigned long ist. char ist nicht notwendigerweise unsigned, so dass folgendes z.B. Murks erzeugt:
    hashSDBM("\x80") -> \x80 = (char)128 = -128 für signed char
    -> hash = -128 + (0<<6) + (0<<16) - 0 = -128 -> Unterlauf
    Ein Compiler sollte da auch eine Warnung bzgl. signed/unsigned mismatch liefern



  • pumuckl schrieb:

    Wobei ich nicht sicher bin, ob das so klug ist, char* als Parameter zu haben, wenn hash ein unsigned long ist. char ist nicht notwendigerweise unsigned, so dass folgendes z.B. Murks erzeugt:
    hashSDBM("\x80") -> \x80 = (char)128 = -128 für signed char
    -> hash = -128 + (0<<6) + (0<<16) - 0 = -128 -> Unterlauf
    Ein Compiler sollte da auch eine Warnung bzgl. signed/unsigned mismatch liefern

    An welcher Stelle genau soll es da eine Warnung geben und warum?
    Würde static_cast<unsigned char>(*strToHash) deine hypothetische Warnung verstummen lassen?

    @Hymir90: Informiere dich, was tatsächlich eine Hash Map ist und tut. Dein Ansatz verwendet den Hash als eindeutigen Schlüssel für die std::map , obwohl natürlich mehrere Elemente den gleichen Hash haben können. Außerdem hat eine Hash Map typischerweise konstante Such- und Einfügezeit, nicht logarithmische wie std::map .



  • out schrieb:

    Hymir90 schrieb:

    jawohl jawohl, ich gebs ja zu! ^^ Ich komm aus der Java-Ecke und hab grad echte Probleme mit den Pointern usw. Danke erstmal für die vielen Antworten. Ich werde mir das mal in Ruhe anschauen!

    Das macht aber gar nichts. Zeiger brauchst du in C++ nur selten. Deswegen kannst du Zeiger erstmal aus deinem Kopf streichen. 😉

    Ach ja? Wie macht ihr dass wenn ihr Referenzen auf Objekte oder sogar Listen mit Referenzen auf Objekte braucht?


  • Mod

    Butterbrot schrieb:

    Das macht aber gar nichts. Zeiger brauchst du in C++ nur selten. Deswegen kannst du Zeiger erstmal aus deinem Kopf streichen. 😉

    Ach ja? Wie macht ihr dass wenn ihr Referenzen auf Objekte oder sogar Listen mit Referenzen auf Objekte braucht?

    Mit Pointern. Aber das brauche ich nur selten. 🙂



  • Butterbrot schrieb:

    Ach ja? Wie macht ihr dass wenn ihr Referenzen auf Objekte oder sogar Listen mit Referenzen auf Objekte braucht?

    Referenzen auf Objekte -> Referenzen. Letzteres kommt so gut wie nie vor ud wird meistens durch Iteratoren ersetzt.

    //und und bei den wenigen Fällen die übrig bleiben Pointer. Aber dann hängt da meistens keine Speicherverwaltung mit dran.



  • Ich Frage nur weil ich mich gerade mit Design Patterns beschäftige und dort ständig Pointer einsetze, dann mache ich wohl was falsch. Kann man denn eine Liste mit Referenzen haben, wie mache ich das mit Null Referenzen? Vielleicht NULL-Objekte erstellen?



  • Ja, Java in C++ ist eine ganz schlechte Idee.



  • Butterbrot schrieb:

    Kann man denn eine Liste mit Referenzen haben, wie mache ich das mit Null Referenzen? Vielleicht NULL-Objekte erstellen?

    Was für eine Liste meinst du eigentlich genau? Am Besten machst du einen eigenen, neuen Thread auf (und verlinkst auf diesen), und zeigst mal ein bisschen. Da kannst du dann deine Fragen und Wünsche äußern... Ansonsten werden wir hier immmer mehr off-topic.



  • Butterbrot schrieb:

    out schrieb:

    Hymir90 schrieb:

    jawohl jawohl, ich gebs ja zu! ^^ Ich komm aus der Java-Ecke und hab grad echte Probleme mit den Pointern usw. Danke erstmal für die vielen Antworten. Ich werde mir das mal in Ruhe anschauen!

    Das macht aber gar nichts. Zeiger brauchst du in C++ nur selten. Deswegen kannst du Zeiger erstmal aus deinem Kopf streichen. 😉

    Ach ja? Wie macht ihr dass wenn ihr Referenzen auf Objekte oder sogar Listen mit Referenzen auf Objekte braucht?

    Wenn ich Listen mit Referenzen auf Objekte brauche, lehne ich mich zurück und überlege, ob ich es wirklich brauche. Das hört sich so an, als wäre es in der Regel ein Designfehler. Und wenn ich wirklich Listen mit Referenzen auf Objekte brauche, dann mache ich das halt. Also dann Listen mit Zeigern. Aber wie Hymir90 richtig sagt: das braucht man halt selten.



  • Ist nur schwierig für mich Design Pattern ohne Zeiger zu implementieren. Hier habe ich einen Thread dazu aufgemacht: http://www.c-plusplus.net/forum/308689

    Ich bin für jede zeigerlose Implementierung eines Design Patterns dankbar.



  • Zeig doch mal ein konkretes Pattern her, das du mit Zeigern implementieren wuerdest.



  • Kellerautomat schrieb:

    Zeig doch mal ein konkretes Pattern her, das du mit Zeigern implementieren wuerdest.

    Warum folgst du nicht dem Link?



  • Uebersehen. 😮


Anmelden zum Antworten