geeksforgeeks example advance c++ iterator containers

c++ - example - La mejor forma de iterar a través de un contenedor



list iterator c++ (7)

A menos que tenga las optimizaciones desactivadas, ambas son equivalentes. En cuanto a i ++ o ++ i, ++ i es más eficiente porque no implica un valor temporal.

¿Cuáles son las ventajas / desventajas de estas dos formas de iteración a través de un contenedor / cuál prefiere y por qué?

for (MyClass::iterator i = m.begin(), e = m.end() ; i != e ; i++) { // ... }

o

for (MyClass::iterator i = m.begin() ; i != m.end() ; i++) { // ... }

Pregunta subsidiaria: i ++ o ++ i? ¿Por qué?


El primero es más rápido porque no se llama a end() en cada iteración. Y no, el optimizador no puede almacenarlo en caché fácilmente, porque no sabe si el tamaño del contenedor ha cambiado en esta iteración (y, por lo tanto, el final se movió). Esto también se aplica a un contenedor de const debido al problema de aliasing.

i++ devuelve una copia de i, luego se incrementa. ++i incrementa, luego devuelve el valor incrementado. Por lo tanto, cuando descarta el valor devuelto, use ++i porque necesita hacer menos trabajo (no copiar). Es muy probable que el optimizador corrija una llamada i++ por lo que es tan rápido como ++i pero no confíe en eso.

¿Yo? yo suelo

for(int i = 0; i < m.size(); i++) { // ... do something with m[i] }

Porque es el más corto y claro. ¿Por qué int y no MyClass::size_type ? Porque es más simple y nunca he tenido que preocuparme por los casos extremos hasta el momento. ¿Por qué i++ ? Porque para los tipos básicos siempre está optimizado en ++i , y es menos confuso para los compañeros de trabajo. Como extra, también puedo usar i como valor numérico. Con un iterador, tendría que mantener un contador separado, o usar std::distance .

obecalp señala que esto no funciona con la mitad de los contenedores estándar, como list y map . De hecho, esos requieren el uso de un iterador adecuado. Relacionado, siempre debe usar un iterator al escribir código genérico.


Para los iteradores de stl normales no hay una gran diferencia, sin embargo, si las colecciones son complejas y pedir el final es caro, solo pedir el final una vez puede ser más rápido.

Del mismo modo para ++ i vs i ++, ++ puedo ser una operación más costosa cuando el iterador es una clase compleja (en lugar de solo un puntero como en los iteradores stl) con i ++ lo que está sucediendo es que está incrementando el iterador pero devolviendo una copia del iterador en su estado anterior. para ++ i devuelve el iterador en su estado actual, por lo que puede devolver una referencia a sí mismo.

Por lo general, lo mejor es optimizar su código solo cuando su perfilador identifique que hay un problema allí; es mejor mantener el código lo más legible posible.


Si el iterador no es trivial (es decir, no es un puntero), ++ i es definitivamente más rápido ya que no implica una copia a un temporal, que puede o no estar optimizado.

La primera forma es un poco más rápida, pero podría ser incorrecta si borra o inserta cosas en el ciclo.

Para una simple iteración sobre un contenedor que uso

#define foreach BOOST_FOREACH // in some header foreach(MyType &element, any_container) { // deal with element }

la mayor parte del tiempo para sucinctness y claridad.


Siempre hago el segundo en realidad, aunque a veces me preocupo si se detienen múltiples llamadas para finalizar. Tenía la impresión de que esto sería optimizado, pero no lo sé con certeza.

Y ++ definitivamente. Nunca es más lento que i ++, si algo es más rápido.


Boost.Foreach presenta una buena manera:

#define foreach BOOST_FOREACH // ... Container<Item> container; // ... foreach (Item item, container) { // do some stuff with the item }


El ciclo C ++ "para cada elemento en contenedor" es el más eficiente donde el contexto no requiere lógica iterativa.

for(Item i : Container) { dosomething(i); }