Eu tenho um código que se parece com isso:
for (std::list<item*>::iterator i=items.begin();i!=items.end();i++)
{
bool isActive = (*i)->update();
//if (!isActive)
// items.remove(*i);
//else
other_code_involving(*i);
}
items.remove_if(CheckItemNotActive);
Gostaria de remover itens inativos imediatamente após atualizá-los, para evitar andar na lista novamente. Mas se eu adicionar as linhas comentadas, recebo um erro quando chego a i++
: "Listador de iterador não incremental". Tentei algumas alternativas que não foram incrementadas na instrução for, mas não consegui fazer nada funcionar.
Qual é a melhor maneira de remover itens enquanto você caminha por uma lista std ::?
Respostas:
Você deve incrementar o iterador primeiro (com i ++) e depois remover o elemento anterior (por exemplo, usando o valor retornado de i ++). Você pode alterar o código para um loop while da seguinte maneira:
fonte
i = items.erase(i)
é mais seguro, porque é equivalente a uma lista, mas ainda funcionará se alguém alterar o contêiner para um vetor. Com um vetor, apague () move tudo para a esquerda para preencher o buraco. Se você tentar remover o último item com um código que incrementa o iterador após a exclusão, o final se move para a esquerda e o iterador se move para a direita - além do final. E então você bate.Você quer fazer:
Isso atualizará corretamente o iterador para apontar para o local após o iterador que você removeu.
fonte
i==items.begin()
?i= items.erase(i);
. É a forma canônica e já cuida de todos esses detalhes.Você precisa fazer a combinação da resposta do Kristo e do MSN:
Obviamente, a coisa mais eficiente e mais eficiente do SuperCool® STL seria algo como isto:
fonte
Use o algoritmo std :: remove_if.
Editar: O trabalho com coleções deve ser como: 1. preparar a coleção. 2. coleção de processos.
A vida será mais fácil se você não misturar essas etapas.
fonte
Aqui está um exemplo usando um
for
loop que itera a lista e incrementa ou revalida o iterador no caso de um item ser removido durante a travessia da lista.fonte
A alternativa para a versão em loop da resposta de Kristo.
Você perde alguma eficiência, retrocede e avança novamente ao excluir, mas em troca do incremento extra do iterador, o iterador é declarado no escopo do loop e o código fica um pouco mais limpo. O que escolher depende das prioridades do momento.
A resposta estava totalmente sem tempo, eu sei ...
fonte
iterator cannot be decremented
Oerase
método precisa de umrandom access iterator
. Algumas implementações de coleção fornecem umforward only iterator
que causa a afirmação.Eu tenho resumo, aqui está o método três com o exemplo:
1. usando
while
loop2. usando a
remove_if
função de membro na lista:3. usando a
std::remove_if
função combinada com aerase
função membro:4. Usando
for
loop, observe o update do iterador:fonte
A remoção invalida apenas os iteradores que apontam para os elementos removidos.
Portanto, neste caso, após remover * i, i é invalidado e você não pode incrementá-lo.
O que você pode fazer é primeiro salvar o iterador do elemento a ser removido, depois incrementar o iterador e depois remover o salvo.
fonte
Se você pensar na
std::list
fila como uma fila, poderá desenfileirar e enfileirar todos os itens que deseja manter, mas desenfileirar apenas (e não enfileirar) o item que deseja remover. Aqui está um exemplo em que quero remover 5 de uma lista que contém os números de 1 a 10 ...myList
agora só terá os números 1-4 e 6-10.fonte
A iteração para trás evita o efeito de apagar um elemento nos elementos restantes a serem atravessados:
PS: veja isto , por exemplo, com relação à iteração reversa.
PS2: Eu não testei completamente se ele lida bem com elementos de apagamento nas extremidades.
fonte
avoids the effect of erasing an element on the remaining elements
para uma lista, provavelmente sim. Para um vetor talvez não. Isso não é algo garantido em coleções arbitrárias. Por exemplo, um mapa pode decidir se reequilibrar.Você pode escrever
Você pode escrever um código equivalente com
std::list::remove_if
, que é menos detalhado e mais explícitoO
std::vector::erase
std::remove_if
idioma deve ser usado quando itens é um vetor em vez de uma lista para manter a compexidade em O (n) - ou caso você escreva código genérico e os itens possam ser um contêiner sem uma maneira eficaz de apagar itens únicos (como um vetor)fonte
Eu acho que você tem um bug lá, eu codigo desta maneira:
fonte