valgrind ausgabe



  • hallo zusammen,

    ich habe folgende valgrind ausgabe:

    ==15746== 62 bytes in 2 blocks are definitely lost in loss record 286 of 775
    ==15746==    at 0x4A085C7: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==15746==    by 0x3780C9B860: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.8)
    ==15746==    by 0x3780C9C364: ??? (in /usr/lib64/libstdc++.so.6.0.8)
    ==15746==    by 0x3780C9C511: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.8)
    ==15746==    by 0x4659CA: TestApplication::handleEvent(AEvent*) (TestApplication.cc:1280)
    ==15746==    by 0x4D2319: EventGroup<AEvent>::sendTo(SubscriberSet, std::string) (AEvent.h:34)
    ==15746==    by 0x42A887: Dispatcher::process() (Dispatcher.cc:791)
    

    an der entsprechenden stelle in der TestApplication wird folgendes gemacht:

    dis->signal( new BEvent("message"));  //TestApplication.cc:1280
    

    Und BEvent ist verkürzt:

    class BEvent : public BEventGroup<BEvent> {
            public:
    
                BEvent(const std::string & s)
                : measurement(s) {
                }
    
            private:
                std::string measurement;
            };
    

    Kann mir jemand erklären, woher der Fehler kommt und wie ich ihn wegbekomme? Valgrind habe ich mit valgrind -v --leak-check=yes aufgerufen.

    Schon mal dank!



  • Wo wird das Event gelöscht?



  • hallo manni,

    in der angegebenen zeile. laut log wird es auch verarbeitet vom eventhandler und der löscht am ende alle events.



  • In der angegebenen Zeile wird nichts gelöscht! Wer sagt, dass der Eventhandler die Events löscht?


  • Mod

    sven_ schrieb:

    in der angegebenen zeile. laut log wird es auch verarbeitet vom eventhandler und der löscht am ende alle events.

    Entweder stimmt diese Aussage nicht und der eventhandler kümmert sich nicht um die Freigabe, obwohl er die Verantwortung für die Ressource hat. Oder der eventhandler ist fehlerhaft programmiert, zum Beispiel könnte er ein Ressourcenhandler sein, der die Regel der großen Drei verletzt.

    Ich tippe mal auf letzteres.



  • hallo zusammen,

    die regel der großen drei????

    der eventhandler ist im dispatcher beheimatet und sieht im process schritt wie folgt aus:

    void
            Dispatcher::process() {
    
                if (pendingObjects.size() > 0) {
    
                    DEBUG("process - Processing " << pendingObjects.size() << " pending objects: " << pendingObjects);
                    DeliverableObject * object;
                    for (auto o = pendingObjects.begin(); o != pendingObjects.end();) {
                        object = *o;
    
                        if (object != NULL) {
                            DEBUG("process - Processing " << object << ", groups: " << object->getGroups());
    
                            GroupList groups = object->getGroups();
                            for (auto g = groups.begin(); g != groups.end(); g++) {
                                SubscriberSet subscribers = subscriptions[*g];
                                DEBUG("process - Type " << *g << " has " << subscribers.size() << " subscribers");
    
                                if (subscribers.size() > 0) {
                                    object->sendTo(subscribers, *g);
                                }
                            }
                        }
                        else {
                            DEBUG("process - Error: Object is NULL! Delivery aborted.");
                        }
    
                        // The iterator <o> used here has to be reinitialized after each
                        // erase operation to ensure its sanity.
                        o = pendingObjects.erase(o);
    
                        DEBUG("process - Finished " << object);
                        DEBUG("process - " << pendingObjects.size() << " objects left.")
                        delete object; //<<--- lösche event ?!
                    }
                    DEBUG("process - Finished processing pending objects.");
                }
            }
    

    Das ganze haben wir selbst geschrieben und basiert auf dem Curiously recurring template pattern.
    http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

    wir nutzen da die type_info einer klasse um sich für einen event zu registrieren. tut eigentlich ganz gut, bis auf das valgrind gemaule. 😃

    Der output sagt:

    DIS@192.168.0.1:100 process - Processing BEvent [Measurement: REJOIN], groups: [EventE, PN6BEventE, PN618BEventE]
    DIS@192.168.0.1:100 process - Type EventE has 1 subscribers
    DIS@192.168.0.1:100 process - Type PN6BEventE has 1 subscribers
    DIS@192.168.0.1:100 process - Finished BEvent [Measurement: REJOIN]
    DIS@192.168.0.1:100 process - 0 objects left.
    

    Daher nehm ich an, dass es auch gelöscht wird bei delete im obigen code. oder irre ich hier?



  • Wie stehen DeliverableObject und BEvent in Beziehung zueinander? Wie werden BEvents in pendingObjects eingefuegt?



  • Hat DeliverableObject einen virtuellen Destruktor? Sonst wird nämlich immer nur das Basisklassenteilobjekt aufgeräumt.



  • Hat DeliverableObject einen virtuellen Destruktor?

    DeliverableObject koennte auch ein BEvent-Zeiger als Member haben, ohne virtuellen Destruktor.



  • knivil schrieb:

    Hat DeliverableObject einen virtuellen Destruktor?

    DeliverableObject koennte auch ein BEvent-Zeiger als Member haben, ohne virtuellen Destruktor.

    Dann ist das gezeigte delete nicht das, welches das Event löscht.



  • manni66 schrieb:

    knivil schrieb:

    Hat DeliverableObject einen virtuellen Destruktor?

    DeliverableObject koennte auch ein BEvent-Zeiger als Member haben, ohne virtuellen Destruktor.

    Dann ist das gezeigte delete nicht das, welches das Event löscht.

    Whatever, der Destruktor kann aber das Event loeschen und dann waere gezeigtes delete dafuer verantwortlich. Es bringt jetzt nichts alle Moeglichkeiten durchzuraten. Es koennte auch ganz anders sein.



  • hallo zusammen,

    sorry, gestern abend war ich unterwegs und hab nicht mehr reingeschaut. freut mich, dass die frage soviel interesse weckt! 😉

    es scheint in der tat der fehlende virtuelle konstruktor gewesen zu sein. diesen hinzugefügt und valgrind ist glücklich. heißt das, wenn delete aufgerufen wurde, dass da nur das deliverableObject gelöscht wurde, und die darauf aufbauenden events blieben übrig?

    was sind nochmal die großen drei?

    ich danke euch vielmals. 😃





  • Bitte beantworte doch erstmal die Frage, wie beide Klassen in Beziehung stehen.

    da nur das deliverableObject gelöscht wurde, und die darauf aufbauenden events blieben übrig

    Das kommt drauf an, wie die Klassen zueinander in Beziehung stehen. Ansosnte: Ja, wenn BEventGroup<BEvent> von DeliverableObject erbt.

    Ansosnten: CRTP nutzen aber Grundlagen nicht verstehen. Irgendwas laeuft falsch.



  • ja, ein event ist ein deliverable object.

    crtp haben wir ja nicht genommen weil es so fancy ist, sondern weil es der einzige weg war, den wir gefunden hatten um das abonnieren von eventgruppen zu ermöglichen. lieber wäre es mir ohne gewesen. 😉



  • nachtrag:

    das man copy constructor, zuweisungs operator und destructor immer angeben soll weiß ich. mir war es bloß nicht unter dem begriff der großen drei geläufig und da der hinweis bezüglich des eventhandlers gemacht wurde auch gerade nicht klar.



  • sven_ schrieb:

    das man copy constructor, zuweisungs operator und destructor immer angeben soll weiß ich.

    Das ist aber falsch. Die Regel der Grossen Drei besagt nur, dass wenn du einen der drei implementierst, du dann meistens auch die anderen zwei brauchst. In C++11 ist es mit Move-Konstruktor und Move-Zuweisungsoperator die Regel der Grossen Fünf.

    Ich würde sogar behaupten, im Allgemeinen ist es gut, wenn man diese Memberfunktionen dem Compiler überlassen kann. Es zeigt nämlich, dass man gut von Low-Level-Operationen wie Speicherverwaltung, Kopieren, etc. abstrahiert hat und sich Objekte selbst kopieren/verschieben können. Gibt natürlich Fälle, wo eine Implementierung trotzdem nötig ist, meist wegen Exceptionsicherheit.

    Interessanter Artikel: Rule Of Zero


Log in to reply