2008-09-25 15 views
5

Al iterar sobre elementos de un vector, se prefiere utilizar iteradores en lugar de un índice (consulte Why use iterators instead of array indices?).Obtener un índice en un vector utilizando Iterators

std::vector<T> vec; 
std::vector<T>::iterator it; 
for (it = vec.begin(); it != vec.end(); ++it) 
{ 
    // do work 
} 

Sin embargo, puede ser necesario utilizar el índice en el cuerpo del bucle. ¿Cuál de los siguientes sería preferible en ese caso, teniendo en cuenta el rendimiento y la flexibilidad/extensibilidad?

  1. Revertir al bucle indexada
     
    std::vector vec; 
    size_t i; 
    for (i = 0; i < vec.size(); ++i) 
    { 
        // use i 
    } 
    
  2. Calcular compensado
     
    std::vector vec; 
    std::vector::iterator it; 
    for (it = vec.begin(); it != vec.end(); ++it) 
    { 
        size_t i = it - vec.begin(); 
        // use i 
    } 
    
  3. uso std :: distancia
     
    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 
    } 
    

Respuesta

13

Si planea utilizar exclusivamente un vector, puede volver al ciclo indexado, ya que transmite su intención más claramente que iterator-loop. Sin embargo, si la evolución de su programa en el futuro puede llevar a un cambio de contenedor, debe apegarse a los iteradores y usar std :: distance, que se garantiza que funcionará con todos los iteradores estándar.

8

El uso de std :: la distancia es un poco más genérico, ya que funciona para todos los iteradores, no solo iteradores de acceso aleatorio. Y debería ser tan rápido como It - vec.begin() en el caso de los iteradores de acceso aleatorio.

It - vec.begin() es básicamente una aritmética de puntero.

4

Revertir al ciclo indexado.

Básicamente en el 90% de los casos, los iteradores son superiores, este es uno de esos 10%. Al usar un iterador, hace que el código sea más complejo y, por lo tanto, más difícil de entender, cuando la razón principal para usar el iterador en primer lugar fue simplificar su código.

+0

Olvidé mencionar el rendimiento, generalmente es seguro asumir que el ciclo indexado tendría un mejor rendimiento, pero el rendimiento sería muy similar en ambos casos. – Guvante

+0

No puedo decir que estoy de acuerdo. El cuerpo del ciclo puede contener otro código que desreferencia al iterador. Los iteradores no están diseñados para simplificar el código, sino que hacen que el código sea más genérico. Al usar los iteradores, puede intercambiar el vector por la lista y aún así funcionaría. – QBziZ

+0

Además, std :: map o std :: set iterators están lejos de ser estúpidos. Si bifurcara todas las teclas posibles, probablemente llevaría una eternidad. Además, tendría que hacer una búsqueda O (log (n)) en cada tecla. Entonces mi ciclo tomaría O (m * log (n)). Usando un iterador, podría recorrer la colección en el tiempo O (n). –

1

Falta una solución: mantener un índice en caso de que lo necesite, pero no lo utilice como una condición de bucle. También funciona en listas, y los costos (por ciclo) son O (n) y un registro adicional.

0

Siempre tendía a mantener iteradores por motivos de desarrollo futuros.

En el ejemplo anterior, si tal vez decidió cambiar std :: vector para std :: set (tal vez necesitaba una colección única de elementos), el uso de iteradores y distancia() continuaría funcionando.

Estoy bastante seguro de que cualquier problema de rendimiento se optimizaría hasta el punto de ser insignificante.

0

Para los vectores, siempre utilizar el método de número entero. Cada índice en el vector tiene la misma velocidad que una búsqueda de matriz. Si voy a utilizar mucho el valor, creo una referencia a él, para mayor comodidad.

iteradores de vectores pueden ser ligeramente más rápidos que un índice en teoría, ya que están usando aritmética de puntero para iterar a través de la lista. Sin embargo, generalmente encuentro que la legibilidad vale la diferencia mínima de tiempo de ejecución.

Uso iteradores para otros tipos de contenedores, y algunas veces cuando no necesita la variable de bucle. Pero si necesita la variable de bucle, no está haciendo nada excepto hacer que su bucle sea más difícil de escribir. (No puedo esperar al auto de C++ 0x)

Cuestiones relacionadas