Anzeige:
Ergebnis 1 bis 10 von 10

Thema: [C++/STL]Wert aus einer Multimap loeschen

  1. #1
    Registrierter Benutzer
    Registriert seit
    22.12.2003
    Beiträge
    19

    [C++/STL]Wert aus einer Multimap loeschen

    Hallo,
    ich habe eine Klasse geschrieben, welche mittles einer Multimap strings mit Integers verknuepft(multimap<string,int>). Die Klasse hat 3 Methoden: check(string), insert(string,int) und delete(string, int).
    Mittels check(string) werden der Reihe nach alle Integer abgearbeitet (In einer weiteren map ist jedem Integer ein Zeiger auf ein Objekt zugeordnet, welches aufgerufen wird, bzw. eine Methode des Objekts), welche mit dem string assoziiert sind:

    Code:
      map<int,meineklasse*> objektmap;
      multimap<string,int> MeineMultimap;
      multimap<string,int>::iterator iter;
      multimap<string,int>::iterator iter_low;
      multimap<string,int>::iterator iter_up;
          
      iter_low=MeineMultimap.lower_bound(MeinString);
      iter_up =MeineMultimap.upper_bound(MeinString);
      
      for(iter=iter_low; iter != iter_up; iter++)
        {
    	  objektmap[iter->second]->meinemethode();
        }
    Mittels insert(string,int) wird ein neuer Wert erstellt:
    Code:
    insert(string Tanga, int Integaer)
    {
        objektmap.insert(make_pair(Integaer, new meineklasse()));
        MeineMultimap.insert(make_pair(Tanga, Integaer));
    }
    Und nun kommt glaube ich (glaube ich nur deshalb hab ich mal so ziemlich alles was mein Problem betreffen koennte hier gepostet) der Knackpunkt und mein Problem.
    Mittels delete wird ein Wert/Integer aus der Multimap geloescht, damit er nicht mehr bei aufrufen von check ¨ausgefuehrt¨ wird:
    Code:
    delete(string Tanga, int Integaer)
    {
      delete objektmap[Integaer];
      objektmap.erase(Integaer);
    
      multimap<string,int>::iterator iter;
      multimap<string,int>::iterator upper;
      multimap<string,int>::iterator lower;
      vector<int> puffer;
    
      upper=MeineMultimap.upper_bound(Tanga);
      lower=MeineMultimap.lower_bound(Tanga);
    
      for(iter=lower; iter!=upper; iter++)
        {
          puffer.push_back(iter->second);
        }
      MeineMultimap.erase(Tanga);
      for(int i=0; i<puffer.size(); i++)
        {
          if(puffer[i]!=Integaer)
    	MeineMultimap.insert(make_pair(Tanga, puffer[i]));
        }
    }
    Ich gehe dabei so vor, dass ich erst die kompletten Werte, welche zu dem jeweiligen Key vorhanden sind kopiere, den Key dann loesche und den Key neu erstelle mit allen gespeicherten werten in puffer, nur ohne den zu loeschenden Wert.
    Ich finde das ganze sieht schon so aus, als koennte es funktionieren das Problem ist jedoch, dass nun nach einem Aufruf von delete und einem darauf folgendem Aufruf von check, zwar nichtmehr das Objekt mit dem Integer, welcher durch delete geloescht werden sollte aufgerufen wird. Jedoch wird nun (glaube ich) der Integer des naechsten strings verarbeitet. Irgendwie funktioniert das loeschen aus der Multimap nicht. Oder kann es sein, dass wenn ich check aufrufe, ohne, dass zu dem Key ein Wert in der Multimap hinterlegt ist (bzw. der Key gar nicht existiert) ¨Mist¨ herauskommt (genauer ein falscher int-wert aufgerufen wird)?

    Ich hoffe ich hab das ganze einigermassen verstaendlich erklaert und dass mir jemand helfen kann... bin schon langsam am Verzweifeln

    Auf jeden Fall schon mal vielen Dank!

    Achja: man moege mir verzeihen, dass ich von integers geredet habe, welche aufgerufen werden, damit meinte ich naetuerlich das damit assoziierte Objekt(bzw. der damit verbundene Zeiger ). Ich denke aber, dass es so verstaendlicher ist.
    Geändert von McRip (28-09-2006 um 02:08 Uhr)

  2. #2
    Registrierter Benutzer
    Registriert seit
    23.05.2004
    Beiträge
    592
    Hallo,
    ich habe eine Klasse geschrieben, welche mittles einer Multimap strings mit Integers verknuepft(multimap<string,int>). Die Klasse hat 3 Methoden: check(string), insert(string,int) und delete(string, int).
    Mittels check(string) werden der Reihe nach alle Integer abgearbeitet (In einer weiteren map ist jedem Integer ein Zeiger auf ein Objekt zugeordnet, welches aufgerufen wird, bzw. eine Methode des Objekts), welche mit dem string assoziiert sind:
    Das hört sich ein bisschen so an als ob du den Boost Multi-Index Container benutzen kannst um dir Arbeit zu ersparen. Vielleicht auch nicht, aber kurz anschauen dürfte nicht schaden.
    http://www.boost.org/libs/multi_index/doc/index.html

    Mittels delete wird ein Wert/Integer aus der Multimap geloescht, damit er nicht mehr bei aufrufen von check ¨ausgefuehrt¨ wird:
    [...]
    Ich gehe dabei so vor, dass ich erst die kompletten Werte, welche zu dem jeweiligen Key vorhanden sind kopiere, den Key dann loesche und den Key neu erstelle mit allen gespeicherten werten in puffer, nur ohne den zu loeschenden Wert.
    Unnütze Arbeit machen, also erst Elemente löschen die dann doch wieder eingefügt werden ist unschön. Das geht bestimmt auch anders. Guck doch mal nach ob du mit binary_search aus <algorithm> direkt das gesuchte Element finden kannst.

  3. #3
    Registrierter Benutzer
    Registriert seit
    21.10.2004
    Beiträge
    8
    Zitat Zitat von locus vivendi Beitrag anzeigen
    Unnütze Arbeit machen, also erst Elemente löschen die dann doch wieder eingefügt werden ist unschön. Das geht bestimmt auch anders. Guck doch mal nach ob du mit binary_search aus <algorithm> direkt das gesuchte Element finden kannst.
    In jeden "Associative Container" kann man erase auch einen iterator - statt eines key - übergeben. Soll heißen

    Code:
      
      upper=MeineMultimap.upper_bound(Tanga);
      lower=MeineMultimap.lower_bound(Tanga);
    
      for(iter=lower; iter!=upper; iter++)
        if (iter->second ==Integaer) MeineMultimap.erase(iter);
    macht was du willst (wenn ich das richtig verstanden habe).

    Apropos verstehen:
    Versteh ich das richtig, das zu jedem string genau ein int gehört und zu jedem int genau eine meineklasse? Warum dann nicht einfach nur eine map<string, meineklasse> ?


    edit:
    Wie unten richtig bemerkt: erase invalidiert den Iterator. Also:
    Code:
      multimap<string,int>::iterator iter1;
      upper=MeineMultimap.upper_bound(Tanga);
      lower=MeineMultimap.lower_bound(Tanga);
    
      for(iter=lower; iter!=upper; iter++)
        if (iter->second ==Integaer) {iter1=iter+1;MeineMultimap.erase(iter);iter=iter1;}
    Geändert von Der Untergeher (29-09-2006 um 01:06 Uhr)

  4. #4
    Registrierter Benutzer
    Registriert seit
    23.05.2004
    Beiträge
    592
    Unnütze Arbeit machen, also erst Elemente löschen die dann doch wieder eingefügt werden ist unschön. Das geht bestimmt auch anders. Guck doch mal nach ob du mit binary_search aus <algorithm> direkt das gesuchte Element finden kannst.
    Upps, da lag ich gleich doppelt daneben. Erstens liefert binary_search keinen Iterator zurück, und zweitens muss die Multimap noch nicht einmal geeignet sortiert sein. Also vergiss binary_search dafür.

    Der erste Satz kann aber stehen bleiben, und Der Untergeher hat ja auch bereits einen Ansatz gepostet wie du nur ein Element entfernst.

  5. #5
    Registrierter Benutzer
    Registriert seit
    22.12.2003
    Beiträge
    19
    Innerhalb einer Schleife, welche von der lower-bound zur upper-bound loopt ein Element mit erase zu löschen funktioniert nicht, da ansonsten der Iterator nicht mehr aktuell ist (mit welchem durchgeloopt wird) und es zu einer Endlosschleife kommen kann.
    Ich habe das ganze nun mit equal_range gelöst und rufe ein erase in der Schleife auf. Das funktioniert soweit nun auch. Das Hauptproblem an der ganzen Sache war, dass ein check eine Methode aufgerufen hat, welche ein delete für sich selbst aufruft... das kann natürlich nicht funktionieren

    Der Untergeher: Ich ordne jedem string ein int, und jedem int einen Objektzeiger zu, da die assoziierten Objektzeiger jeweils über einen string, als auch über einen Integer "ansprechen" können möchte. Wobei jedem string mehrere Objekte zugeodnet werden können und jedem int nur ein Objekt.

    Vielen Dank auf jeden Fall euch beiden!

  6. #6
    Registrierter Benutzer
    Registriert seit
    23.05.2004
    Beiträge
    592
    Innerhalb einer Schleife, welche von der lower-bound zur upper-bound loopt ein Element mit erase zu löschen funktioniert nicht, da ansonsten der Iterator nicht mehr aktuell ist (mit welchem durchgeloopt wird) und es zu einer Endlosschleife kommen kann.
    Ich hatte das so verstanden, dass du maximal ein Element entfernen musst. Dann wäre das kein Problem, weil du nach dem Entfernen die Schleife einfach abbrechen kannst. Wenn du andererseits auf mehrere Elemente die zu entfernen sind stößt, kannst du, um nur mit gültigen Iteratoren zu arbeiten so vorgehen:
    In einer Schleife entscheide ob das Element entfernt werden soll
    - wenn ja, dann mach eine Kopie des aktuellen Iterators,
    inkrementiere den aktuellen Iterator und schließlich
    lösche das Element mit der Kopie.
    - wenn nein, dann inkrementiere den aktuellen Iterator.

    Übrigens wird in der nächsten Ausgabe des C++-Standards erase wahrscheinlich einen Iterator zurückgeben, wodurch eine solche Schleife kompakter sein würde.

  7. #7
    Registrierter Benutzer
    Registriert seit
    18.03.2005
    Beiträge
    211
    Übrigens wird in der nächsten Ausgabe des C++-Standards erase wahrscheinlich einen Iterator zurückgeben, wodurch eine solche Schleife kompakter sein würde.
    Macht das die M$ impl ned jetzt scho ?
    Und ja waer praktischer weil:
    - wenn ja, dann mach eine Kopie des aktuellen Iterators,
    inkrementiere den aktuellen Iterator und schließlich
    lösche das Element mit der Kopie.
    IMHO wenn man eine manipulation (loeschen einfuegen) auf assoziative container ausfuehrt, ist nicht sichergestellt das aktuelle iteratoren geultig bleiben .... sprich wenn du dir den iterator erhoehst und merkst, und dan erase mittels den alten iterator ausfuehrst, kein dein neuer iterator genau so in den wald zeigen ....

    Rein theorethisch muesstest nach nem erfolgreichen loeschvorgang wieder komplett neu suchen ....

    Ciao ...

  8. #8
    Registrierter Benutzer
    Registriert seit
    23.05.2004
    Beiträge
    592
    Zitat:
    Übrigens wird in der nächsten Ausgabe des C++-Standards erase wahrscheinlich einen Iterator zurückgeben, wodurch eine solche Schleife kompakter sein würde.

    Macht das die M$ impl ned jetzt scho ?
    Ja, ich glaube auch. Die Implementierung die Microsoft liefert stammt von Dinkumware. Deren Doku sagt das ein Iterator zurückgeliefert wird.

    Und ja waer praktischer weil:

    Zitat:
    - wenn ja, dann mach eine Kopie des aktuellen Iterators,
    inkrementiere den aktuellen Iterator und schließlich
    lösche das Element mit der Kopie.
    IMHO wenn man eine manipulation (loeschen einfuegen) auf assoziative container ausfuehrt, ist nicht sichergestellt das aktuelle iteratoren geultig bleiben .... sprich wenn du dir den iterator erhoehst und merkst, und dan erase mittels den alten iterator ausfuehrst, kein dein neuer iterator genau so in den wald zeigen ....
    Das ist allerdings nicht richtig. Einfügen in die assoziativen Container macht keine Iteratoren ungültig. Und entfernen nur die, welche auf das entfernte Element zeig(t)en.

    Der Standard sagt das in Abschnit 23.1.2 "Associative containers", Absatz 8:
    "The insert members shall not affect the validity of iterators and references to the container, and the erase
    members shall invalidate only iterators and references to the erased elements."

    Zum Thema hier noch mal ein Beitrag von Andrew Koenig:
    http://www.ddj.com/blog/cppblog/arch...innest_of.html

  9. #9
    Registrierter Benutzer
    Registriert seit
    23.05.2004
    Beiträge
    592
    Ich habe aus den Postings falsch zitiert, bitte den Text im Kopf richtig zuordnen...

  10. #10
    Registrierter Benutzer
    Registriert seit
    18.03.2005
    Beiträge
    211
    Der Standard sagt das in Abschnit 23.1.2 "Associative containers", Absatz 8:
    Ok, wenns im Standard so definiert ist ...

    Hatte aber schonmal probleme solcher Art mit irgendwas ... wer weiss mit was ich das da wieder verwechselt hab ^^

    Ciao ...

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •