O que acontece se você chamar erase () em um elemento do mapa enquanto iterar do início ao fim?

No código a seguir, faço um loop em um mapa e teste se um elemento precisa ser apagado. É seguro apagar o elemento e manter a iteração ou preciso coletar as chaves em outro recipiente e fazer um segundo loop para chamar o erase ()?

map::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: Claro, então eu li essa pergunta que eu não acho que seria relacionada, mas responde a minha pergunta.

C ++ 11

Isso foi corrigido no C ++ 11 (ou o apagamento foi aprimorado / tornado consistente em todos os tipos de contêiner).
O método de exclusão agora retorna o próximo iterador.

 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

Apagar elementos em um mapa não invalida nenhum iterador.
(além dos iteradores no elemento que foi excluído)

Na verdade, inserir ou excluir não invalida nenhum dos iteradores:

Veja também esta resposta:
Mark Ransom Technique

Mas você precisa atualizar seu código:
Em seu código você incrementa pm_it depois de chamar de apagar. Neste momento é tarde demais e já está invalidado.

 map::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 } } 

Veja como eu faço isso …

 typedef map 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 ... } } 

É assim que eu faria, aproximadamente:

 bool is_remove( pair val ) { return val.second == delete_this_id; } map::iterator new_end = remove_if (port_map.begin( ), port_map.end( ), is_remove ); port_map.erase (new_end, port_map.end( ) ); 

Há algo estranho sobre

 val.second == delete_this_id 

mas acabei de copiá-lo do seu código de exemplo.