2010-09-19 20 views
12

Ha habido algunas preguntas con respecto a este problema antes; Tengo entendido que llamar al std::vector::erase solo invalidará los iteradores que están en una posición después de el elemento borrado. Sin embargo, después de borrar un elemento, ¿el iterador en esa posición sigue siendo válido (siempre que, por supuesto, no apunte a end() después del borrado)?std :: invalidación de iterador de vector

Mi comprensión de cómo se implementaría un vector parece sugerir que el iterador es definitivamente útil, pero no estoy del todo seguro de si podría conducir a un comportamiento indefinido.

Como un ejemplo de lo que estoy diciendo, el siguiente código elimina todos los enteros impares de un vector. ¿Este código causa un comportamiento indefinido?

typedef std::vector<int> vectype; 
vectype vec; 

for (int i = 0; i < 100; ++i) vec.push_back(i); 

vectype::iterator it = vec.begin(); 
while (it != vec.end()) { 
    if (*it % 2 == 1) vec.erase(it); 
    else ++it; 
} 

El código funciona bien en mi máquina, pero eso no me convence de que sea válido.

Respuesta

31

después de borrar un elemento, es el iterador en esa posición siendo válida

No; todos los iteradores en o después del (los) iterador (es) pasados ​​a erase son invalidados.

Sin embargo, erase devuelve un nuevo iterador que apunta al elemento inmediatamente después del elemento (s) que se borraron (o hasta el final si no hay tal elemento). Puede usar este iterador para reanudar la iteración.


Tenga en cuenta que este método particular de eliminación de elementos extraños es bastante ineficiente: cada vez que eliminar un elemento, todos los elementos después de que se tienen que mover una posición a la izquierda en el vector (esto es O (n)). Puede realizar esta tarea de manera mucho más eficiente utilizando el erase-remove idiom (O (n)). Se puede crear un is_odd predicado:

bool is_odd(int x) { return (x % 2) == 1; } 

Entonces esto se puede pasar a remove_if:

vec.erase(std::remove_if(vec.begin(), vec.end(), is_odd), vec.end()); 
+1

¿Por qué se pasa por referencia x' 'const en lugar de por ¿valor? – fredoverflow

+0

@Fred: ninguna razón en particular; gracias por señalar eso. –

+0

@James Pero, ¿cómo funciona el código anterior en cuestión, ya que borrar invalidará los iteradores? – Kapil

0

O:

class CIsOdd 
{ 
public: 
    bool operator()(const int& x) { return (x % 2) == 1; } 
}; 

vec.erase(std::remove_if(vec.begin(), vec.end(), CIsOdd()), vec.end()); 
+1

¿Por qué pasa 'x' por const reference en lugar de por valor? – fredoverflow

+2

Pregunta: ¿por qué la gente a menudo prefiere el enfoque aquí (functor con solo operador() sobrecargado, es decir, sin estado/datos) frente a una función independiente simple como en la respuesta de James McNellis anterior? Entiendo que ambos funcionarán, pero suelo adoptar el mismo enfoque que James, para mí parece más simple y más obvio. En cierto punto, empiezo a preguntarme: "¿Qué me estoy perdiendo?" Si se trata de preferencias personales, está bien. – Dan

+0

@FredOverflow, x puede ser una estructura, @Dan, ... y operador() un miembro de esa estructura – ssianky

Cuestiones relacionadas