¿Por qué borrar un elemento del mapa mientras se está recorriendo no provoca un bloqueo cada vez que ocurre?
Aquí está mi función:
void Timers::RemoveTimer(DWORD id)
{
auto it = m_mapTimers.begin();
for ( ; it != m_mapTimers.end(); ++it) {
if (it->first.second == id) {
m_mapTimers.erase(it);
}
}
}
Y claramente no debería eliminar el elemento de esta forma, pero lo que me interesa es por qué el fallo no es constante. El programa puede llamar a esta función varias miles de veces hasta que se cae.
Además, como una pregunta secundaria, ¿por qué no hubo fallos en C++98? Los obtengo después de portar a C++20, sin cambios en la clase.
davy.ai
La función dada
Timers::RemoveTimer()
atraviesa el mapam_mapTimers
utilizando un iteradorit
, y elimina el elemento si el segundo valor de la clave coincide con elid
dado. Sin embargo, al eliminar un elemento de un mapa se invalidan todos los iteradores que apuntan a ese elemento o a cualquier otro elemento posterior. Por lo tanto, cuando el bucle continúa iterando después de eliminar un elemento,it
ahora apunta a un iterador invalidado.En C++98, este problema podría no haber causado fallas porque el estándar no era tan estricto en cuanto a lo que provoca que un iterador se invalide. Sin embargo, en C++20, el estándar se ha vuelto más riguroso en cuanto a las situaciones en las que un iterador se invalida, lo que lleva a una falla en este caso.
Para resolver este problema, el bucle debería utilizar
std::map::erase()
directamente en el elemento que coincide con elid
dado, y actualizar el iteradorit
en consecuencia utilizando el valor de retorno deerase()
. Aquí está la función actualizada:Esta función revisada elimina correctamente el elemento que coincide con el
id
dado, sin invalidar ningún iterador.