2012-09-24 14 views
5

he declarado un vector como¿Debo iterar un vector por iterador o por operador de acceso?

std::vector<int> MyVector; 
MyVector.push_back(5); 
MyVector.push_back(6); 
MyVector.push_back(7); 

¿Cómo debo usar en un bucle?

¿Al iterarlo con un iterador?

for (std::vector<int>::iterator it=MyVector.begin(); it!=MyVector.end(); ++it) 
{ 
    std::cout << "Vector element (*it): " << *it << std::endl; 
} 

¿O por su iterador de acceso?

for (std::vector<int>::size_type i=0; i<MyVector.size(); i++) 
{ 
    std::cout << "Vector element (i) : " << MyVector.at(i) << std::endl; 
} 

En los ejemplos que encontré en Internet se usan ambos. ¿Es uno de ellos superior al otro en todas las condiciones? Si no, ¿cuándo debería preferir uno de ellos sobre el otro?

+1

qué no el nombre * "iterador" * ayuda con la decisión? Por cierto, espero que tengas un claro entendimiento de lo que 'std :: vector :: at' hace y por qué lo usas en tu código. Si se usa 'std :: vector :: at' en lugar de' std :: vector :: operator [] ', los iteradores probablemente siempre sean más rápidos (sin tener en cuenta otras ventajas). –

Respuesta

5

El primer formato es más genérico formato para iterar sobre los contenedores de la biblioteca estándar por lo que es más común e intuitiva. Si necesita cambiar su contenedor, este código de iteración no se verá afectado. Funcionará para cada tipo de contenedor de biblioteca estándar, por lo tanto, le brinda un código más genérico.

En segundo formato, std::vector::at() comprueba los límites cada vez que se llama en cada iteración, por lo que puede ser un poco perjudicial para el rendimiento. Esta sobrecarga no está presente en el primer formato, ya que no hay límites de comprobación involucrados. Tenga en cuenta que es el mismo caso con el uso de operator[].
Tenga en cuenta que el retraso en el rendimiento no es tanto como lo notará, a menos que esté trabajando con datos enormes.

+0

Concur. En pocas palabras: use iteradores para escanear, en() para acceso aleatorio. Estaras contento de haberlo hecho. – WhozCraig

+0

@CraigNelson No, no lo haré. Si tengo acceso al vector fuera de límites, me avergüenzo (y UB), pero no me haga verificar su tamaño todas las veces. En el modo de depuración obtendré una aserción de todos modos (al menos en VC++). –

+0

@ChristianRau si tiene acceso aleatorio a una secuencia sin conocer los límites que le corresponden. Prefiero saber eso antes de tiempo. Tienes toda la razón, sin embargo. Quise decir [] en lugar de en(). touche. – WhozCraig

3

El uso de std::vector's [] operator es probablemente más rápido porque usar std::vector::at() dentro de un bucle for comprueba el tamaño del vector dos veces (en el bucle for y en la comprobación de límites de std :: vector :: at()).

El primer método se puede utilizar en otros contenedores y, por lo tanto, puede ayudar mucho cuando cambie el tipo de contenedor.

Si usa C++ 11, use bucles basados ​​en rangos. una basada gama-

2

En primer lugar, si usted tiene 11 C++, utilizar para:

for (auto i : MyVector) 
{ 
    std::cout << i; 
} 

O BOOST_FOREACH en C++ 03:

BOOST_FOREACH(int& i, MyVector) 
{ 
    std::cout << i; 
} 

O std::copy:

std::copy(MyVector.begin(), 
      MyVector.end(), 
      std::ostream_iterator<int>(std::cout, "\n")); 

En cuanto a, la pregunta en cuestión, at() comprueba que el índice está dentro de los límites y arroja una excepción si no lo es. Por lo tanto, no lo use a menos que necesite esa verificación adicional. La primera forma en que la tienes es estándar y funciona bien. Algunas personas son pedante e incluso se escriben así:

for (std::vector<int>::iterator it=MyVector.begin(), end = MyVector.end(); it!= end; ++it) 
{ 
    std::cout << "Vector element (*it): " << *it << std::endl; 
} 

En lo anterior que el iterador en caché en lugar de llamar endend() cada bucle. Si esto realmente hace una diferencia en el rendimiento o no, no lo sé.

1

No hay "uno es superior al otro" (salvo que casi nunca desea utilizar at()at() sólo es apropiada si existe algo que realmente puede hacer para recuperarse del error). El uso de iterador vs. índice es en gran parte de estilo, y el mensaje está pasando. La forma más idiomática de C++ de hacer las cosas sería el iterador , pero las personas procedentes de otros entornos (por ejemplo, los matemáticos ) encontrarán que la indexación es más idiomática.

Hay donde hay una distinción real:

  • El idioma iterador trabajará con otros tipos de recipientes. Este puede ser relevante si existe una posibilidad real de que utilice otros contenedores .

  • La expresión de indización puede usar un único índice para varios contenedores diferentes . Si está iterando a través de varios vector con el mismo tamaño , el uso de la expresión de indización aclara que está accediendo al el mismo elemento en cada uno de los vector. (Una vez más, esto parece ocurrir con mayor frecuencia en aplicaciones matemáticas.)

  • Por último, cada vez que realmente estamos haciendo de acceso aleatorio, o calcular el elemento de ninguna manera, la utilización de índices es probablemente más intuitiva. (En estos casos, es probable que desee hacer los cálculos en int, solamente convertir a size_t en el último momento.)

Cuestiones relacionadas