Melhor maneira de in situ excluir um elemento

votos
2

Eu tenho um conjunto de objetos que eu iterar, no entanto I pode decidir durante a iteração que um (ou mais) desses objetos agora precisam ser eliminados.

Meu código é o seguinte:

if( ! m_Container.empty() )
    {
        for(  typedefedcontainer::iterator it = m_Container.begin();
              it != m_Container.end(); 
              ++it  )
        {
            if( ! ( SomeFunction( (*it), test, TEST!, false ))  )
            {
            // If function returns false, delete object.
                m_Container.erase( it );
                AsyncResponseStore::iterator it = m_asyncResponses.begin();
            }

        }


    }

Mas é claro que, quando eu apagar um objeto que eu recebo um erro: Mapa / set iterador não Incrementable. Alguém pode sugerir uma maneira melhor de fazer isso?

Veja: O que acontece se você chama apagar () em um elemento do mapa durante a iteração do início ao fim?

Publicado 09/12/2008 em 17:09
fonte usuário
Em outras línguas...                            


3 respostas

votos
6

Se o recipiente suporta (que eu suspeito que o seu não, mas o título da pergunta é genérica assim que este pode ser útil aos outros se não você):

struct SomePredicate {
    bool operator()(typedefedcontainer::value_type thing) {
        return ! SomeFunction(thing, "test", "TEST", false);
    }
};

typedefedcontainer::iterator it;
it = std::remove_if(m_Container.begin(), m_Container.end(), SomePredicate());
m_Container.erase(it, m_Container.end());

m_Container deve ter um método intervalo de apagamento, o que inclui qualquer sequência ou associativa recipiente. Ele tem que ter um iterador mutável, embora, e eu só notei que eu originalmente interpretado mal a mensagem de erro: ele diz que "mapa / set iterador não Incrementable". Então eu acho que o recipiente é um mapa ou um conjunto.

Note-se que os três últimos poderia ser um one-liner verdadeiramente maravilhosa, mas esta margem é muito estreita para contê-lo.

Também que SomePredicate poderia ter um construtor com parâmetros para armazenar os parâmetros adicionais para SomeFunction, já que na vida real eu acho que eles são não-constante.

Você realmente pode se livrar de SomePredicate completo, se você usar boost: bind para construir o functor. Seu one-liner, então, seria verdadeiramente maciça.

[Edit: Rob Walker observa corretamente em sua resposta uma suposição de que eu faço aqui e que a questão não diz, o que é que todos apagamento pode ser adiada até depois do iterate-and-teste é feito. Se SomeFunction acessa m_Container por um caminho oculto (por exemplo, uma global, ou porque SomeFunction é realmente uma função membro deste), e seus resultados dependem do conteúdo do recipiente, em seguida, o meu código pode não ser equivalente ao código do questionador. Mas eu acho que o meu código é o "a menos que haja uma razão para não" default.]

Respondeu 09/12/2008 em 17:39
fonte usuário

votos
6

Depende do recipiente. O recipiente lista suporta eliminação durante a enumeração, retornando uma nova iteração do método de apagamento que representa o próximo item na lista. Mapa não suporta isso.

Um método simples de mapa é acumular os itens que deseja apagar em uma lista separada e, em seguida, iterar sobre essa lista quando tiver terminado o processamento do mapa para apagar os itens do mapa. Isso pressupõe que você pode adiar a eliminação até a iteração foi concluída. Se não, então você não tem escolha, mas o reinício da iteração para cada exclusão.

Respondeu 09/12/2008 em 17:18
fonte usuário

votos
0

Fixa a seguinte redacção:

for(  typedefedcontainer::iterator it = m_Container.begin();
      it != m_Container.end(); 
        )
{
    if( ! ( SomeFunction( (*it), "test", "TEST!", false ))  )
    {
    // If function returns false, delete object.
        m_Container.erase( it++ );
    }
    else
    { 
        ++i;
    } 

}

Quando um elemento for excluído, todos os ponteiros para se tornar invalidado. Portanto, utilizando-++ chegarmos em torno dele. Obrigado a todos aqueles que postou sugestões.

Respondeu 09/12/2008 em 17:30
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more