
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.

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
}
}
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 ...
}
}
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.
9866400cookie-checkWas passiert, wenn Sie erase() für ein Kartenelement aufrufen, während Sie von Anfang bis Ende iterieren?yes
Bitte beachten Sie in Frage, dass
std::remove_if
funktioniert nicht mitstd:map
– Buchsenpaar
4. November 2015 um 13:16 Uhr