Was passiert, wenn Sie erase() für ein Kartenelement aufrufen, während Sie von Anfang bis Ende iterieren?

Lesezeit: 4 Minuten

Was passiert wenn Sie erase fur ein Kartenelement aufrufen wahrend
Matthäus Smith

Im folgenden Code durchlaufe ich eine Map und teste, ob ein Element gelöscht werden muss. Ist es sicher, das Element zu löschen und weiter zu iterieren, oder muss ich die Schlüssel in einem anderen Container sammeln und eine zweite Schleife ausführen, um das Löschen () aufzurufen?

map<string, SerialdMsg::SerialFunction_t>::iterator pm_it;
for (pm_it = port_map.begin(); pm_it != port_map.end(); pm_it++)
{
    if (pm_it->second == delete_this_id) {
        port_map.erase(pm_it->first);
    }
}

UPDATE: Natürlich habe ich dann diese Frage gelesen, von der ich nicht dachte, dass sie verwandt wäre, aber meine Frage beantwortet.

  • Bitte beachten Sie in Frage, dass std::remove_if funktioniert nicht mit std:map

    – Buchsenpaar

    4. November 2015 um 13:16 Uhr

Was passiert wenn Sie erase fur ein Kartenelement aufrufen wahrend
Martin York

C++11

Dies wurde in C++11 behoben (oder das Löschen wurde verbessert/über alle Containertypen hinweg konsistent gemacht).
Die Erase-Methode gibt nun den nächsten Iterator zurück.

auto pm_it = port_map.begin();
while(pm_it != port_map.end())
{
    if (pm_it->second == delete_this_id)
    {
        pm_it = port_map.erase(pm_it);
    }
    else
    {
        ++pm_it;
    }
}

C++03

Durch das Löschen von Elementen in einer Zuordnung werden keine Iteratoren ungültig.
(abgesehen von Iteratoren auf dem gelöschten Element)

Das tatsächliche Einfügen oder Löschen macht keinen der Iteratoren ungültig:

Siehe auch diese Antwort:
Mark-Ransom-Technik

Aber Sie müssen Ihren Code aktualisieren:
In Ihrem Code erhöhen Sie pm_it nach dem Aufrufen von Erase. An diesem Punkt ist es zu spät und bereits ungültig.

map<string, SerialdMsg::SerialFunction_t>::iterator pm_it = port_map.begin();
while(pm_it != port_map.end())
{
    if (pm_it->second == delete_this_id)
    {
        port_map.erase(pm_it++);  // Use iterator.
                                  // Note the post increment.
                                  // Increments the iterator but returns the
                                  // original value for use by erase 
    }
    else
    {
        ++pm_it;           // Can use pre-increment in this case
                           // To make sure you have the efficient version
    }
}

  • Die Reihenfolge der Auswertung des Inkrements im Postfix-Ausdruck pm_it++ garantiert ausgeführt werden, bevor die Funktion eingegeben wird?

    – David Rodríguez – Dribeas

    3. März 2011 um 20:56 Uhr

  • @David Rodríguez – dribeas: Ja. Der Standard garantiert, dass alle Argumentausdrücke vollständig ausgewertet werden, bevor die Funktion aufgerufen wird. Es ist das Ergebnis des Post-Inkrements, das an die Erase-Funktion () übergeben wird. Also ja, das Post-Inkrement von pm_it wird durchgeführt, bevor erase() aufgerufen wird.

    – Martin York

    3. März 2011 um 21:19 Uhr

  • HINWEIS: Fast Zeile für Zeile stimmt mit dem assoziativen Containerbeispiel in Scott Meyers „Effective STL“ Punkt 9 überein.

    – Oger Psalm33

    9. Mai 2012 um 15:33 Uhr

  • for (auto pm_t = port_map.begin(); pm_it != port_map.end(); ) { … }

    – Andrey Syrokomskiy

    25. September 2013 um 9:42 Uhr


  • @iboisver: Auf dem Vektor. Die Verwendung von erase() macht alle Iteratoren des Arrays nach dem Löschpunkt ungültig (nicht nur das Ende), dies ist eine Eigenschaft von Sequence Behälter. Die besondere Eigenschaft von Associative container besteht darin, dass Iteratoren nicht durch Löschen oder Einfügen ungültig werden (es sei denn, sie zeigen auf ein Element, das gelöscht wurde). Vektor- und Erase-Usign-Iteratoren werden ausführlich in der entsprechenden Frage unter stackoverflow.com/a/3938847/14065 behandelt

    – Martin York

    29. August 2014 um 17:35 Uhr


So mache ich das …

typedef map<string, string>   StringsMap;
typedef StringsMap::iterator  StrinsMapIterator;

StringsMap m_TheMap; // Your map, fill it up with data    

bool IsTheOneToDelete(string str)
{
     return true; // Add your deletion criteria logic here
}

void SelectiveDelete()
{
     StringsMapIter itBegin = m_TheMap.begin();
     StringsMapIter itEnd   = m_TheMap.end();
     StringsMapIter itTemp;

     while (itBegin != itEnd)
     {
          if (IsTheOneToDelete(itBegin->second)) // Criteria checking here
          {
               itTemp = itBegin;          // Keep a reference to the iter
               ++itBegin;                 // Advance in the map
               m_TheMap.erase(itTemp);    // Erase it !!!
          }
          else
               ++itBegin;                 // Just move on ...
     }
}

  • Wenn Sie auch das Ende des Vektors löschen (itEnd), erfolgt die letzte Prüfung (die while-Bedingung) gegen einen ungültigen Iterator (itEnd). Nicht gut.

    – Agostino

    28. Februar 2015 um 23:03 Uhr

So würde ich es ungefähr machen:

bool is_remove( pair<string, SerialdMsg::SerialFunction_t> val )
{
    return val.second == delete_this_id;
}

map<string, SerialdMsg::SerialFunction_t>::iterator new_end = 
    remove_if (port_map.begin( ), port_map.end( ), is_remove );

port_map.erase (new_end, port_map.end( ) );

Es ist etwas Seltsames dabei

val.second == delete_this_id

aber ich habe es gerade aus deinem Beispielcode kopiert.

986640cookie-checkWas passiert, wenn Sie erase() für ein Kartenelement aufrufen, während Sie von Anfang bis Ende iterieren?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy