C++ in std::map Pointer auf Funktionsobjekte speichern

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 31.08.2011 15:17:34

Hi,

ich hatte die Idee Funktionsobjekte (also eine Klasse mit dem operator()) aufzurufen wenn ein bestimmter String in den Daten auftaucht. Dazu wollte ich den String als Index und die Objekte über den Basisklassen Pointer in ein std::map einfügen. Soweit das es der Compiler übersetzen mag bin ich gekommen. Leider wills nicht laufen. :(

Code: Alles auswählen

general protection ip:7f8a757cabd9 sp:7fff3b82bed8 error:0 in libstdc++.so.6.0.13[7f8a75723000+f6000]
... so siehts aus:

Code: Alles auswählen

// Das ist ein Template die Instanz wird so erzeugt:
  hts::EventList<std::string, hts::Event<std::string, std::map<std::string, std::string> > > xmlEvents;

// Mit diesen zwei Template Parametern wird dann die Map erzeugt.
  std::map<eventId, eventTyp*> vecIntEventListe;

// So versuche ich das dann wieder zu benutzen.
  (*vecIntEventListe[Id]) ();
Ich habe beim herum suchen im Netz den Hinweis gefunden das das mit std::map und Pointern auf Objekte nicht funktioniert. Ich weiß aber nicht warum das nicht gehen sollte. Map speichert zwar immer eine Referenz auf das was da rein soll aber das wäre ja nicht wirklich ein Hindernis. Oder übersehe ich da was wichtiges?

Grüße
Alexander

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 31.08.2011 18:22:57

Na mein Schuss ins blaue wäre, dass die die Map etwa so füllst:

Code: Alles auswählen

void FillMap()
{
  MyFuncObj obj;
  vecIntEventListe[Id] = &obj;
}
Du musst sicherstellen, dass die Objekte, später noch existieren und nicht per Destuktor zerstört wurden. Die Adresse auf die dann der Pointer in der Map ist dann immer noch die alte Adresse, welche aber "unbewohnt" ;) ist.

Pack doch das Funktionsobjekt direkt in die Map. So kannst du mit dem Ding dann auch noch Stateinformationen sammeln/auswerten wenn du fertig bist mit dem Bearbeiten. So stellst du sicher dass die Objekte noch existeren wenn du darauf zugreifst.

Was dann aber der Fall ist

Code: Alles auswählen

void FillMap()
{
  MyFuncObj obj;
  vecIntEventListe[Id] = obj; // [1]
}
[1] // hier wird obj dann per Copy Constructor in die Map kopiert und anschliessend beim Verlasen der FillMap() Funktion das objekt "obj" zerstört. Seine Kopie lebt aber in der map weiter.

Gruß
schorsch

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 31.08.2011 18:37:33

Danke für die schnelle Antwort.

Ich habe mal eine Textausgabe in den Destruktor eingebaut. Die wird aber nicht ausgegeben.

So sieht die Methode aus zum füllen der Map:

Code: Alles auswählen

// Registriere ein neues Event.
template<class eventId, class eventTyp>
void EventList<eventId, eventTyp>::regEvent (eventId Id, eventTyp *Event)
{
  vecIntEventListe[Id] = Event;
}
Alexander

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 31.08.2011 19:27:55

Code: Alles auswählen

// Registriere ein neues Event.
template<class eventId, class eventTyp>
void EventList<eventId, eventTyp>::regEvent (eventId Id, eventTyp *Event)
                                                                   ^^^^^
{
  vecIntEventListe[Id] = Event;
}
Kuck dir das mal an. Du gibts hier nen Pointer in die Funktion.

Falls du eben unterschiedliche Klassen von Funktionsobjekten haben musst, dann musst du über pointer gehen. Entweder über raw pointer oder über shared_ptr<>. Entweder boost oder C++11 (ehemals C++0x)
Das würde dann bei mir etwa so aussehen:

Code: Alles auswählen

typedef std::string eventId; // oder wass immer benötigt wird

// Registriere ein neues Event.
template<class eventTyp>
void EventList<eventTyp>::regEvent (eventId Id) // id muss nicht
{
  vecIntEventListe[Id] =  (std|boost)::shared_ptr<EventTypeBaseClass>(new eventTyp);
}
std::map<eventId, (std|boost)::shared_ptr<EventTypeBaseClass> > vecIntEventListe; // deklaration der Eventliste müsste so aussehen.

SharedPtr haben den Vorteil, dass du dich hier nicht mehr um die Lebenszeit der Funktionsobjeke kümmern musst.

Gruß
schorsch

EDIT: Auf dem Pastebin hab ich ein Beispiel gepostet, das kompiliert mit

Code: Alles auswählen

gcc --std=c++0x -lstdc++ main.cpp 
NoPaste-Eintrag35886

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 31.08.2011 20:10:49

Warum man da den shared_pointer braucht ist mir noch unklar. Aber ich probier das gleich mal aus. Zur Info noch die Event-Basisklasse.

Die Basisklasse sieht so aus. Über diesen wollte ich dann alle Events übergeben die mit den selben Template Parameter erzeugt wurden. Deshalb der Pointer ...

Code: Alles auswählen

template <class eventResult, class eventTyp>
class Event
{
public:
  virtual void operator() (void);
};
Grüße
Alexander

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 31.08.2011 20:35:01

Na der Pointer ist nötig, da du ja ein abstraktes Interface hast und die konkrete Implementierung über das Interface der Basisklasse aufrufen musst. Die map kann ja nur einen Typ als Ziel des Keys enthalten und nicht x beliebige Typen.

Also geht der Weg für den Zugriff:
ID ---map id to pointer--> Pointer (Basisklasse)
Pointer (Basisklasse) ---vtable--> Konkrete Implementierung

Die Templateklasse Event ist ja keine Klasse die du in die map packen kannst. Du kannst immer nur eine konkrete Instanzierung der Klasse in die Map geben. Ein template ist eben eine Vorlage für eine Klasse und keine Klasse selbst.

Vorlage = Template

Code: Alles auswählen

template <class T>
class list
{
   ...
};
Konkrete Instantierung

Code: Alles auswählen

list<int> Meine_Integer_Liste;
Das könntest du auch wieder in die map packen. b sp

Code: Alles auswählen

std::map<MyKey, list<int> > MeineKeyToIntListeMap;
EDIT:
Damit du noch auf die Objekte in der Map zugreifen kannst und dich nicht mehr ums delete aller Funktionsobjekte kümmern musst, hab ich hier dem shared_ptr<> eingebastelt. Du kannst das natürlich auch manuell machen ;)

Falls du noch Fragen hast oder ich das hier komplett missverstehe könnten wiur auch per Chat das klären ;)

EDIT2:
Noch eine Frage:
Warum hat has template Event zwei template Argumente? (<class eventResult, class eventTyp>)
EventResult kann ich soweit nachvollziehen, aber warum EventTyp? Der EventTyp ist doch die konkrete Implementierung/Ableitung des Events.

Dein Problem im Eingangspost ist ja in Kurzform (std:.string = id ---> spezielles Event in map aufrufen) ist.

Gruß
schorsch

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 31.08.2011 21:40:21

Du verstehst das schon richtig. Ich wollte Events mit verschiedenen Datentypen bauen können deshalb die zwei Template Parameter. Bei der Klasse Event ist der erste ein möglicher Rückgabewert und der zweite für die möglichen Übergabeparameter. Die ich aber noch nicht benutze in dem bisherigen Beispiel deshalb konntest Du auch nicht sehen wozu die gut sein sollen und der Templ-Parameter-Name ist auch noch falsch :? . Bei der Klasse EventListe ist der erste der Map-Index und der zweite ein Pointer auf eine konkrete Instanz der Event Basisklasse.

Warum man einen Pointer braucht ist mir schon klar. Was mir unklar war warum einen shared_ptr ich dachte das müsste auch mit einem normalen gehen. Hast Du jetzt aber auch geschrieben in Deinem EDIT. Beim shared_ptr müsste ich dann nicht mehr selbst darüber nachdenken ob diese Adresse noch bewohnt ist.

Ich habe das ja auch mit einem Pointer gemacht aber halt einem normalen. Wohl wahr das es mit dem shared_ptr einfacher ist weil er dafür sorgt das die Instanz am leben bleibt solange sie gebraucht wird. Werd ich mal versuchen ...

Deinen EDIT2 habe ich ja eigentlich am Anfang dieses Textes mit beantwortet. EventTyp sollte besser EventParameter genannt werden. Das sah alles mal ganz anders aus und ist auch noch nicht fertig. Ich habe das nur nicht zum laufen bekommen mit dem Funktionsobjekt in der Map. Aber ich denke derweil schadet ein Template-Parameter der nicht benutzt wird auch nicht.

Stimmt :D : std:.string = id ---> spezielles Event in map aufrufen == ganz traurig weil Crash :( .
... leider erfüllt diese Bedingung ...

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 31.08.2011 21:52:19

Du benötigst eine Basisklasse ohne Templateparameter die nur die vtable aufbaut (Also das Interface das von Aussen dann über die map benutzt wird).
dann leitest du die template Vorlage von dieser Basisklasse ab.

Code: Alles auswählen

template <class eventResult, class eventTyp>
class Event : public EventBase // Eventbase hat die virtuelle Methode(n) die du dann aufrufst
{
public:
  virtual void operator() (void); // falls dieser operator überall so aufgerufen werden soll, muss er ins Interface (EventBase) als pure virtual (=0)
};
Das sieht dann etwa so aus

Code: Alles auswählen

std::map<eventId, EventBase* > vecIntEventListe; // deklaration der Eventliste müsste so aussehen.


Event<MyResult, MyParamType>* evt = new Event<MyResult, MyParamType>;
vecIntEventListe["Meine ID"] = evt;
Gruß
schorsch

EDIT:
Die Spezialisierung des templates Event<MyResult, MyParamType>::operator()(void) kann dann MyResult und MyParamType benutzen. Nach "aussen" sichtbar über die map ist das dann nicht. Das könnte man über ein Visitor Design Pattern [1] lösen

[1] http://de.wikipedia.org/wiki/Visitor

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 31.08.2011 22:08:08

Oh, darf ein Template nichts virtuelles haben?

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 31.08.2011 22:14:12

Kannst du schon haben, nur ist das template ja noch keine Klasse deren Pointer du in die map packen kannst.
Das template ist ja ein Gerüst. EventBase mit den pure virtual Methoden stellt dann das Interface zu Verfügung und das template implementiert diese dann.

Event<int, std::string>
Event<std::string, std::string>

Das sind 2 komplett unterschiedliche Klassen für den Compiler. Das einzigste was sie gemeinsam haben ist die Vorlage.

EDIT:
Was mir noch auffällt:

Code: Alles auswählen

// So versuche ich das dann wieder zu benutzen.
  (*vecIntEventListe[Id]) ();
Falls Id nicht in der map enthalten ist, erstellt die map automatisch einen neuen Eintrag mit dem Key. ABER: map<key,value> value wird mit dem default construktor instantiert, was bei pointern in der map null ergibt. Ergo: Potentieller Crash, wenn du vergessen hast für diese Id ein Funktionsobjekt zu hinterlegen.

also besser so:

Code: Alles auswählen

EventCont::iterator pos = vecIntEventListe.find(id);
if (pos != vecIntEventListe.end())
   (*pos->second)();

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 31.08.2011 22:30:46

Hab ich ja:

Code: Alles auswählen

// So hab ich z.B. ein Event gebaut.
class insertEvent : public Event<std::string, std::map<std::string, std::string> >
{
public:
  insertEvent ()
  {
    syslog (LOG_INFO, "insertEvent::insertEvent ()");
  }

  ~insertEvent ()
  {
    syslog (LOG_INFO, "insertEvent::~insertEvent ()");
  }

  void operator () ()
  {
    syslog (LOG_INFO, "Geht das so wie ich es meine");
  }
};

// So dann eine automatische Instanz davon.
insertEvent xmlInsert;

// Diese dann so an EventList übergeben.
xmlEvents.regEvent ("insert", &xmlInsert);
Meiner Meinung nach liegt das Problem nicht an dem drumherum.

Code: Alles auswählen

// Registriere ein neues Event.
template<class eventId, class eventTyp>
void EventList<eventId, eventTyp>::regEvent (eventId Id, eventTyp *Event)
{
// Wenn ich das Event nicht in die Map stelle sondern in der regEvent Methode ausführe geht das ganz problemlos.
  (*Event) ();
}
sondern entweder daran wie ich den Pointer an die Map zuweise oder daran wie ich das Ding wieder auszuführen versuche.

Grüße
Alexander

EDIT: Also für diesen Testfall gibts den Index in der Map sicher. Ich schreib die da als fixe Konstanten rein (zum Testen halt soll nicht so bleiben). Für später ist Dein Verbesserungsvorschlag eine gute Sache den übernehme ich gerne wenn ich darf.
Zuletzt geändert von alexander_ro am 31.08.2011 22:35:14, insgesamt 1-mal geändert.

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 31.08.2011 22:34:52

Code: Alles auswählen

// So dann eine automatische Instanz davon.
insertEvent xmlInsert;

// Diese dann so an EventList übergeben.
xmlEvents.regEvent ("insert", &xmlInsert);
Das scheint das Problem zu sein. wenn xmlInsert out of scope geht, ist der pointer in der map ungültig. Ergo bei zugriff darüber -> Crash

Ok .. hab verstanden. du mcht ds ganze innerhalb einer Klasse die eh ein template mit den eventResult/eventTyp ist. Dachte dass du die events nur per template erzeugst, aber nicht in einer template klasse benutzt.

Kein Crash:

Code: Alles auswählen

{
   // So dann eine automatische Instanz davon.
   insertEvent xmlInsert;

   // Diese dann so an EventList übergeben.
   xmlEvents.regEvent ("insert", &xmlInsert);
   (*vecIntEventListe["insert"]) (); // xmlInsert noch im scope
}
Crash:

Code: Alles auswählen

{
   {
   // So dann eine automatische Instanz davon.
      insertEvent xmlInsert;

      // Diese dann so an EventList übergeben.
      xmlEvents.regEvent ("insert", &xmlInsert);
   }
   (*vecIntEventListe["insert"]) (); // xmlInsert nicht mehr im scope
}
Zuletzt geändert von schorsch_76 am 31.08.2011 22:41:46, insgesamt 1-mal geändert.

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 31.08.2011 22:41:41

Die erstelle ich in der Aufrufenden Klasse als privat. Die sollten doch dann bis zum zerstören der Instanz erhalten bleiben?
Wenn xmlInsert zerstört würde müsste doch auch im Syslog der Text auftauchen den ich da ausgebe? tut er aber nicht

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 31.08.2011 22:43:44

Mach einfach mal sowas:

Code: Alles auswählen

    // Diese dann so an EventList übergeben.
      xmlEvents.regEvent ("insert", new insertEvent);

Übelstes Speicherleck, aber das insertEvent ist sicher noch am leben wenn du daruf zugreifst, da es uf dem Heap liegt.

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 31.08.2011 22:47:30

alexander_ro hat geschrieben:Die erstelle ich in der Aufrufenden Klasse als privat. Die sollten doch dann bis zum zerstören der Instanz erhalten bleiben?
Wenn xmlInsert zerstört würde müsste doch auch im Syslog der Text auftauchen den ich da ausgebe? tut er aber nicht
Bleibt die aufrufende Klasse so lange am Leben (und ihre Member)? Ist vecIntEventListe ein Member der aufrufenden Klasse?
Zuletzt geändert von schorsch_76 am 31.08.2011 22:56:32, insgesamt 1-mal geändert.

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 31.08.2011 22:55:54

Och ich bau auch Speicherlecks ein wenn Du das sagst :wink:
EDIT: ging aber trotzdem nicht

vecIntEventListe ist ein Privates Member von EventList. Die Klasse EventList soll darin die Events verwalten. Eine Instanz von EventList wird auch von der aufrufenden Klasse erzeugt und ja die lebt so lange. Ich lasse alle Konstruktoren und Destruktoren ein »ich bin da« ins Syslog schreiben. Dort tauchen aber nur Konstruktoren auf.

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 31.08.2011 22:59:27

alexander_ro hat geschrieben:Och ich bau auch Speicherlecks ein wenn Du das sagst :wink:
EDIT: ging aber trotzdem nicht

vecIntEventListe ist ein Privates Member von EventList. Die Klasse EventList soll darin die Events verwalten. Eine Instanz von EventList wird auch von der aufrufenden Klasse erzeugt und ja die lebt so lange. Ich lasse alle Konstruktoren und Destruktoren ein »ich bin da« ins Syslog schreiben. Dort tauchen aber nur Konstruktoren auf.
Ok .. dann liegt es nicht an der Lebenszeit der Objekte sondern am Zugriff darauf. Zeig doch mal den Auszug auf den Zugriff auf das insert Element.

Evtl pass den zugriff darauf wie folgt an:

Code: Alles auswählen

std::map<eventId, eventTyp*>::iterator pos = vecIntEventListe.find(id);
if (pos != vecIntEventListe.end())
   (*pos->second)(); // hier kann auch (*vecIntEventListe["insert"]) (); stehen. Der zugriff über pos ist nur performanter, da nicht neu gesucht werden muss
else
   syslog (LOG_INFO, "Houston: Wir haben ein Problem! Id nicht in Map enthalten");
Es könnte sein, dss die geparsten ids das Problem sind, und bsp "insert" eingefügt wird und aus dem Parser kommt "insert " oder "Insert".
Zuletzt geändert von schorsch_76 am 31.08.2011 23:14:12, insgesamt 1-mal geändert.

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 31.08.2011 23:13:31

Ah jetzt gehts ...
Du willst sicher nicht wissen woran es gelegen hat. Oder doch?

Hm, ich trau mich das ja gar nicht sagen ähm schreiben. Für EventList hatte ich die Ausgabe im Konstruktor vergessen und blöderweise war das der üble Täter.
Eigentlich wollte ich das wie die Events in der Klasse privat definieren. Noch blöderweise habe ich das aber nicht gemacht sondern im Konstruktor und der ist halt leider irgendwann zu Ende und damit das Objekt an dieser Adresse wieder ausgezogen. :roll:

Tschuldigung wegen der vielen Arbeit aber ich habs echt nicht gesehen.

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 31.08.2011 23:15:59

alexander_ro hat geschrieben:Ah jetzt gehts ...
Du willst sicher nicht wissen woran es gelegen hat. Oder doch?

Hm, ich trau mich das ja gar nicht sagen ähm schreiben. Für EventList hatte ich die Ausgabe im Konstruktor vergessen und blöderweise war das der üble Täter.
Eigentlich wollte ich das wie die Events in der Klasse privat definieren. Noch blöderweise habe ich das aber nicht gemacht sondern im Konstruktor und der ist halt leider irgendwann zu Ende und damit das Objekt an dieser Adresse wieder ausgezogen. :roll:

Tschuldigung wegen der vielen Arbeit aber ich habs echt nicht gesehen.
Ich kenne das Problem. Du sitzt davor und siehst den Wald nicht, weil einfach viel zu viele Bäume vor dir stehen ;)

Macht ja nix, ich mach sowas gern. Das schärft meine Intuition wo Probleme herkommen können :)

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 31.08.2011 23:26:53

Ich finds immer doof wenn ich sowas nicht finde. Aber ich hatte mehr an einen Fehler bei den Events gedacht oder dann eben das mit der Map. Aber wie sagt man ... falsch gedacht. :wink:

Danke für Deine Hilfe und gute Nacht ...
Alexander

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 01.09.2011 13:53:51

Den Zugriff auf die Map habe ich jetzt mit einem iterator und find gemacht damit nicht versehentlich Einträge mit NULL-Pointern entstehen. Das funktioniert auch super.
sieht nun so aus:

Code: Alles auswählen

template<class eventId, class eventTyp>
void EventList<eventId, eventTyp>::sendEvent (eventId Id)
{
  try
  {
    typename std::map<eventId, std::shared_ptr<eventTyp> >::iterator pos = vecIntEventListe.find (Id);

    if (pos != vecIntEventListe.end())
      (*pos->second) ("");
    else
      syslog (LOG_INFO, "EventList::sendEvent: Event-ID nicht vorhanden");
  }
  catch (...)
  {
    syslog (LOG_INFO, "EventList::sendEvent: unbekannte Exception");
    exit (1);
  }
}
Wegen Deinem Vorschlag mit den shared_ptr<> hätte ich noch eine Frage. Ich würde ja gerne automatisch oder dynamisch (new) erzeugte Events benutzen können. Weil ja shared_ptr und automatisches Objekt nicht recht sinnvoll ist geht das dann nur über normale Pointer.
Seh ich doch richtig?

Grüße
Alexander

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 01.09.2011 16:33:13

Ja da hast du recht. Objekte auf dem Stack und shared_ptr<> passen nicht zusammen. shared_ptr<> werden IMMER mir dynamisch allokiertem Speicher verwendet.

Du legst die neuen Funktionsobjekte dann so in die map (dort wo du momentan die Objekte in die map packst)

Code: Alles auswählen

vecIntEventListe[Id] =  std::shared_ptr<EventKlasse>(new EventKlasse);
Diese shared_ptr<> entsorgen dann die mit new angelegten Objekte wenn niemand mehr diese referenziert (der use_counter == 0 ist). Sprich in deinem Fall wenn die Map zerstört wird.

Code: Alles auswählen

xmlInserter inserter;
vecIntEventListe[Id] =  std::shared_ptr<EventKlasse>(&inserter); // kompilert zwar, aber der inserter wird ja vom Stack wieder entsorgt und der shared_ptr<> "meint" er hat die Verantwortung zur Entsorgung des Objektes. Doppeltes delete == böser crash
GRuß
schorsch

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 02.09.2011 11:44:01

Funktioniert so ja schon recht gut. Aber ist etwas unpraktisch weil ...

Code: Alles auswählen

template <class eventResult, class eventParam> class Event {}

template <class eventId, class eventTyp> class EventList {}
der bei der Spezialisierung von Event entstehenden Typ muss dann ja genauso bei EventList als Template Parameter übergeben werden. Wäre schön wenn man sowas automatisieren könnte. Da genau genommen bei EventList noch ein Template Parameter für die Parameter fehlt die man dem Event mitgeben können soll. Das wäre dann noch eine Abhängigkeit die man von Hand pflegen muss.
  • Mit einem typedef könnte man das sicher vereinfachen aber schön ist anders.

    Wenn man die Klasse Event innerhalb von EventList definiert könnten beide Klassen die gleichen Template Parameter benutzen. Ich habe bedenken das der Compiler das verhackstücken will wenn einer der Template Parameter aus der Spezialisierung des Templates entsteht. :roll:
Weiss wer was besseres?

Grüße
Alexander

EDIT: Ist mir noch eingefallen: für eine häufiger benutzt Spezialisierung von Event und EventList könnte ich ja Standarddatentyp für die Template Parameter festlegen. In diesem Fall wäre das dann recht einfach zu Nutzen.

EDIT2: Noch eine Idee: ich dachte zuerst nur daran Event in das Template EventList zu verlegen das geht aber glaube ich nicht. Anders herum müsste es gehen. Das Template Event könnte für sich selbst auch Liste sein.

Benutzeravatar
schorsch_76
Beiträge: 2607
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von schorsch_76 » 02.09.2011 14:47:39

Ich habe bedenken das der Compiler das verhackstücken will wenn einer der Template Parameter aus der Spezialisierung des Templates entsteht.
Warum sollte der Compiler das verhackstücken?

Wirf mal nen Blick in die STL oder Boost. Dort werden auch permanent typedefs erzeugt und genutzt.

Da ich leider nicht den Quellcode vorliegen habe, kann ich hier leider nur im Nebel stochern.

Einer meiner beliebtesten typedefs ist bsp. solch einer:

Code: Alles auswählen

template <class T>
class MyTemClass
{
public:
  typedef boost::shared_ptr<myTemClass<T>> SharedPtr;
};

// Meine Version
MyTemClass<int>::SharedPtr p_test = MyTemClass<int>::SharedPtr(MyTemClass<int>);

// ohne typedef
boost::shared_ptr<MyTemClass<int>> p_test = boost::shared:_ptr<MyTemClass<int>>(MyTemClass<int>);
Das setze ich sehr sehr häufig ein, da es mir sehr hilft. Auch für spezielle Container mache ich IMMER typedefs.

Code: Alles auswählen

typedef std::list<MyTemClass<int>> TemClassCont;
TemClassCont m_data;

for (TemClassCont::iterator pos = m_data.begin(); pos != m_data.end(); ++pos)
{
 ....
}
Hier tausche ich nur im typedef den Container typen aus und alle Schleifen (egal ob for_each oder solche manuellen) sind angepasst. Insbesondere bei grossen klassen ist das nützlich.

Ebenfalls nutzt die STL bsp solche typedefs:
/usr/include/c++/4.4.6/bits/std_list.h

Code: Alles auswählen


113     struct _List_iterator
 114     {
 115       typedef _List_iterator<_Tp>                _Self;
 116       typedef _List_node<_Tp>                    _Node;
 117 
 118       typedef ptrdiff_t                          difference_type;
 119       typedef std::bidirectional_iterator_tag    iterator_category;
 120       typedef _Tp                                value_type;
 121       typedef _Tp*                               pointer;
 122       typedef _Tp&                               reference;
 123 

Also: Warum nicht auch typedefs nutzen ;) Sie sind teil der Sprache und ein mächtiges Werkzeug.

Gruß
schorsch

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ in std::map Pointer auf Funktionsobjekte speichern

Beitrag von alexander_ro » 02.09.2011 17:01:05

Projektseite mit der aktuelle Sourcecode Version.
Athena-Projekt: http://www.hts-software.de/index.php?id=11

HtsApi_1.0/Event ist der Pfad zu den Templates.

Grüße
Alexander

EDIT: Die schwierigkeit ist das der Typedef in EventList in Abhängigkeit von Event erfolgen müsste. Ich habe es vorerst mit einem Typedef bei der Klasse die die Events aufruft gemacht. In diesem Fall zu finden in HtsApi/Xml

Code: Alles auswählen

  typedef Event<std::string, std::string> xmlEventTyp;
  typedef EventList<std::string, xmlEventTyp> xmlEventListTyp;

Antworten