invalidação de iterador std :: vector

Houve algumas perguntas sobre esse assunto antes; meu entendimento é que chamar std::vector::erase só invalidará os iteradores que estão em uma posição após o elemento apagado. No entanto, após apagar um elemento, o iterador nessa posição ainda é válido (desde que, claro, não aponte para end() após o apagamento)?

Meu entendimento de como um vetor seria implementado parece sugerir que o iterador é definitivamente utilizável, mas não tenho certeza se isso poderia levar a um comportamento indefinido.

Como exemplo do que estou falando, o código a seguir remove todos os inteiros ímpares de um vetor. Esse código causa um comportamento indefinido?

 typedef std::vector 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; } 

O código roda bem na minha máquina, mas isso não me convence de que é válido.

depois de apagar um elemento, o iterador nessa posição ainda é válido

Não; todos os iteradores no ou após o (s) iterador (es) passado (s) para erase são invalidados.

No entanto, erase retorna um novo iterador que aponta para o elemento imediatamente após o (s) elemento (s) que foram apagados (ou para o final, se não houver tal elemento). Você pode usar este iterador para retomar a iteração.


Note que este método particular de remover elementos ímpares é bastante ineficiente: cada vez que você remove um elemento, todos os elementos após ele precisam ser movidos uma posição para a esquerda no vetor (isto é O (n 2 )). Você pode realizar essa tarefa de maneira muito mais eficiente usando o idioma de exclusão de exclusão (O (n)). Você pode criar um predicado is_odd :

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

Então isso pode ser passado para remove_if :

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

Ou:

 class CIsOdd { public: bool operator()(const int& x) { return (x % 2) == 1; } }; vec.erase(std::remove_if(vec.begin(), vec.end(), CIsOdd()), vec.end());