Obter um índice num vector utilizando Iterators
Pergunta
Quando iteração sobre elementos de um vector, é preferível usar iterators em vez de um índice (ver por que usar iteradores em vez de índices de matriz? ).
std::vector<T> vec;
std::vector<T>::iterator it;
for ( it = vec.begin(); it != vec.end(); ++it )
{
// do work
}
No entanto, pode ser necessário usar o índice no corpo do ciclo. Qual dos seguintes seria preferível nesse caso, considerando o desempenho e flexibilidade / extensibilidade?
- Reverter ao indexada loop
std::vector vec; size_t i; for ( i = 0; i < vec.size(); ++i ) { // use i }
- Calcular offset
std::vector vec; std::vector::iterator it; for ( it = vec.begin(); it != vec.end(); ++it ) { size_t i = it - vec.begin(); // use i }
- Use std :: distância
std::vector vec; std::vector::iterator it; for ( it = vec.begin(); it != vec.end(); ++it ) { size_t i = std::distance( vec.begin(), it ); // use i }
Solução
Se você estiver planejando usar exclusivamente um vetor, você pode querer voltar ao lacete indexada, uma vez que transmite a sua intenção mais claramente do que iterador-loop. No entanto, se a evolução do seu programa no futuro pode levar a uma mudança de recipiente, você deve ficar com os iteradores e uso std :: distância, o que é garantido que funcione com todos iterators padrão.
Outras dicas
Usando std :: distância é um pouco mais genérica, uma vez que funciona para todos os iteradores, não apenas iteradores de acesso aleatório. E deve ser tão rápido como ele -. Vec.begin () em caso de iteradores de acesso aleatório
-. Vec.begin () é basicamente a aritmética de ponteiro
std::distance(vec.begin(), it)
lhe dará o índice it
está apontando para, assumindo que pontos em vec
.
Carl
Reverter ao lacete indexada.
Basicamente em 90% dos casos, iteradores são superiores, este é um daqueles 10%. Usando um iterador que você está fazendo o código mais complexo e, portanto, mais difícil de entender, quando toda a razão para usar o iterador em primeiro lugar foi para simplificar o seu código.
Você está perdendo uma solução: manter um índice no caso de você precisar dele, mas não usá-lo como uma condição de loop. Obras em listas também, e os custos (por loop) são O (n) e um registo extra.
Eu sempre tendem para manter com iterators por razões de desenvolvimento futuro.
No exemplo acima, se você talvez decidiu trocar a std :: vector para std :: set (talvez você precisava de uma colecção única de elementos), usando iteradores e distância () iria continuar a trabalhar.
I certeza de que quaisquer problemas de desempenho seria otimizado ao ponto de ser insignificante.
Para vetores, eu sempre usar o método inteiro. Cada um índice para o vector é a mesma velocidade como uma pesquisa de matriz. Se eu vou estar usando o valor de um monte, eu criar uma referência a ele, por conveniência.
iterators vetor pode ser ligeiramente mais rápido do que um índice em teoria, uma vez que eles estão usando a aritmética de ponteiro para percorrer a lista. No entanto, geralmente eu acho que a leitura vale a pena a diferença de tempo de execução mínimo.
Eu uso iterators para outros tipos de contêineres, e às vezes quando você não precisa a variável de loop. Mas se você precisa a variável loop, você não está fazendo nada além de fazer o seu circuito mais difícil tipo. (Eu não posso esperar para auto c ++ 0x de ..)