container - list push c++
list iterator no incrementable (8)
Tengo un proyecto viejo que fue desarrollado usando Visual Studio 2003 y lo recompuse con vs2005 recientemente. Sin embargo, durante el tiempo de ejecución, recibo el siguiente error:
list iterator no incrementable
Rastreé el programa a esta función:
void InputQueue::update()
{
list<PCB>::iterator iter;
list<PCB>::iterator iterTemp;
for(iter = begin(); iter != end(); iter++)
{
if(iter->arrivalTime == 0)
{
ReadyQueue::getInstance()->add(*iter);
iterTemp = iter;
iter++;
erase(iterTemp);
}
}
}
No soy un experto en C ++ y esto es lo que el depurador de VS me consiguió. ¿Alguien podría explicarme cuál es el problema?
Gracias
¿Puedo sugerir un algoritmo más simple?
La función gratuita std::remove_if
se puede usar para dividir tu lista en 2, elementos que coinciden o no coinciden con el predicado (es decir, arrivalTime == 0). Devuelve el iterador separando los rangos. Luego puede llamar a ReadyQueue::getInstance()->add(subrange_begin, subrange_end)
(usted tiene esa sobrecarga, ¿verdad?) Y borrar el subrange luego.
Solo un caso donde puede usar algoritmos STL en lugar de escribir sus propios bucles.
Creo que Chris tiene razón. Sin embargo, otro problema podría deberse al hecho de que usted asigna al iterador. - ¿Se garantiza que los iteradores de lista sean asignables? Sin mirar el estándar, no lo creo porque la asignabilidad no se menciona en ninguna parte en la documentación SGI de los iteradores.
Esto es solo una nota al margen, pero importante.
Supongo que heredas de std::ist<PCB>
. Debo decir que heredar para reutilizar la funcionalidad no siempre me ha ido bien. Pero como también estás ''heredando'' el proyecto, no hay mucho que hacer al respecto ...
La causa raíz es "list.erase ()" cambiará el iterador. La escritura correcta para el ciclo "for":
for (list<CMessage*>::iterator it=que.begin(); it!=que.end(); ++it)
{
if(m_type == (*it)->m_type)
{
delete *it;
it=que.erase(it); //"list.erase()" will change the iterator!!!
if(it==que.end()) break; //Check again!!!
//still has side effect here. --it?
}
}
Pero todavía tiene un efecto secundario, por lo que la solución de Mark será la mejor.
Si obtiene el "iterador de lista incompatible", probablemente se deba a que dentro de su "ReadyQueue :: getInstance () -> add (* iter);" está cambiando algo en * iter que hace que el algoritmo hash devuelva un valor diferente para borrar de lo que lo hizo durante la inserción.
Tenga en cuenta que si iter->arrivalTime == 0
, entonces el iterador de la lista se incrementa dos veces: una vez antes de la eliminación del elemento, y una vez más al final del ciclo.
Si el elemento que se va a eliminar es el último elemento de la lista, obviamente, esto no funcionará correctamente. Me atrevo a decir que nunca funcionó correctamente incluso en VS2003, pero VS2005 te alerta sobre ello mejor. :-)
Recuerde, es un comportamiento indefinido iterar pasado end()
. Absolutamente puede suceder cualquier cosa, como un bloqueo del programa o (en este caso) un mensaje de error.
Volvería a escribir tu ciclo para que sea como el siguiente:
while (iter != end())
{
if (iter->arrivalTime == 0)
{
ReadyQueue::getInstance()->add(*iter);
iter = erase(iter);
}
else
{
++iter;
}
}
Ahora está correctamente recorriendo la lista revisando cada índice.
Voy a eludir algunas líneas de tu código para mostrar dónde está el problema:
for(iter = begin(); iter != end(); iter++) // ***
{
if(iter->arrivalTime == 0)
{
iter++; // ***
}
}
En las dos líneas marcadas con ***, está incrementando el iterador. El problema es que en la segunda de las dos líneas, no verifica que no haya llegado al final del contenedor. Efectivamente, si ingresas al ciclo interno, estás incrementando dos veces, pero solo verificando si puedes incrementar una vez.
Una solución es comprobar si estás al end()
antes de hacer el segundo incremento, pero me parece que estás tratando de realizar la misma operación que hace un rato en mi pregunta con el filtrado de elementos desde un contenedor ( un mapa en ese caso, pero lo mismo aplica para la mayoría de los contenedores STL).