usar sirve recorrer que para imprimir for ejemplo con c++ stl iterator

c++ - sirve - ¿Por qué usar iteradores en lugar de índices de matriz?



recorrer list integer java (25)

Separación de intereses

Es muy bueno separar el código de iteración de la preocupación ''central'' del bucle. Es casi una decisión de diseño.

De hecho, la iteración por índice lo vincula con la implementación del contenedor. Al solicitar al contenedor un iterador de inicio y fin, se habilita el código de bucle para usar con otros tipos de contenedores.

Además, en la forma std::for_each , le std::for_each a la colección qué hacer, en lugar de preguntarle algo sobre sus aspectos internos

El estándar 0x introducirá cierres, lo que hará que este enfoque sea mucho más fácil de usar. Observe el poder expresivo de, por ejemplo, Ruby''s [1..6].each { |i| print i; } [1..6].each { |i| print i; } [1..6].each { |i| print i; }

Actuación

Pero tal vez un problema muy supervisado es que, al utilizar el enfoque for_each se obtiene una oportunidad de paralelizar la iteración. ¡Los bloques de subprocesos Intel pueden distribuir el bloque de código sobre la cantidad de procesadores en el sistema!

Nota: después de descubrir la biblioteca de algorithms , y especialmente para cada persona, pasé dos o tres meses escribiendo contraseñas de operadores "ayudantes" ridículamente pequeñas que volverán locos a los demás desarrolladores. Después de este tiempo, volví a un enfoque pragmático: los cuerpos de bucles pequeños no merecen la foreach nunca más :)

Una referencia obligada en los iteradores es el libro "Extended STL" .

El GoF tiene un pequeño párrafo al final del patrón de iterador, que habla de esta marca de iteración; se llama un ''iterador interno''. Echa un vistazo here , también.

Tome las siguientes dos líneas de código:

for (int i = 0; i < some_vector.size(); i++) { //do stuff }

Y esto:

for (some_iterator = some_vector.begin(); some_iterator != some_vector.end(); some_iterator++) { //do stuff }

Me han dicho que se prefiere la segunda vía. ¿Por qué exactamente es esto?


Ambas implementaciones son correctas, pero preferiría el bucle ''for''. Como hemos decidido utilizar un Vector y no cualquier otro contenedor, la mejor opción sería utilizar índices. El uso de iteradores con vectores perdería el beneficio de tener los objetos en bloques de memoria continuos que ayudan a facilitar su acceso.


Aparte de todas las otras excelentes respuestas ... es posible que int no sea lo suficientemente grande para tu vector. En su lugar, si desea usar la indexación, use size_type para su contenedor:

for (std::vector<Foo>::size_type i = 0; i < myvector.size(); ++i) { Foo& this_foo = myvector[i]; // Do stuff with this_foo }


Después de haber aprendido un poco más sobre el tema de esta respuesta, me doy cuenta de que fue una simplificación. La diferencia entre este bucle:

for (some_iterator = some_vector.begin(); some_iterator != some_vector.end(); some_iterator++) { //do stuff }

Y este bucle:

for (int i = 0; i < some_vector.size(); i++) { //do stuff }

Es bastante mínimo. De hecho, la sintaxis de hacer bucles de esta manera parece estar creciendo en mí:

while (it != end){ //do stuff ++it; }

Los iteradores desbloquean algunas características declarativas bastante potentes, y cuando se combinan con la biblioteca de algoritmos STL, se pueden hacer algunas cosas geniales que están fuera del alcance de la administración de índices de matriz.


Durante la iteración no es necesario saber la cantidad de elementos que se procesarán. Solo necesitas el elemento y los iteradores hacen esas cosas muy bien.


Es parte del moderno proceso de adoctrinamiento de C ++. Los iteradores son la única forma de iterar la mayoría de los contenedores, por lo que lo usa incluso con vectores solo para entrar en la mentalidad adecuada. En serio, esa es la única razón por la que lo hago, no creo que haya reemplazado un vector con un tipo de contenedor diferente.

Wow, esto todavía está siendo bajado después de tres semanas. Supongo que no vale la pena ser un poco irónico.

Creo que el índice de matriz es más legible. Coincide con la sintaxis utilizada en otros idiomas y con la sintaxis utilizada para los arrays C anticuados. También es menos detallado. La eficiencia debería ser un lavado si su compilador es bueno, y casi no hay casos en los que sea importante.

Aun así, todavía me encuentro usando iteradores frecuentemente con vectores. Creo que el iterador es un concepto importante, por lo que lo promuevo siempre que puedo.


Es posible que desee utilizar un iterador si va a agregar / eliminar elementos al vector mientras está iterando sobre él.

some_iterator = some_vector.begin(); while (some_iterator != some_vector.end()) { if (/* some condition */) { some_iterator = some_vector.erase(some_iterator); // some_iterator now positioned at the element after the deleted element } else { if (/* some other condition */) { some_iterator = some_vector.insert(some_iterator, some_new_value); // some_iterator now positioned at new element } ++some_iterator; } }

Si estuvieras usando índices, tendrías que barajar los elementos arriba / abajo en la matriz para manejar las inserciones y eliminaciones.


Imagine some_vector se implementa con una lista enlazada. Luego, solicitar un elemento en el i-ésimo lugar requiere que se realicen operaciones para recorrer la lista de nodos. Ahora, si usa iterador, en términos generales, hará su mejor esfuerzo para ser lo más eficiente posible (en el caso de una lista enlazada, mantendrá un puntero al nodo actual y lo avanzará en cada iteración, requiriendo solo un sola operación).

Así que proporciona dos cosas:

  • Abstracción de uso: solo quieres iterar algunos elementos, no te importa cómo hacerlo
  • Actuación

Incluso mejor que "decirle a la CPU qué hacer" (imperativo) es "decirle a las bibliotecas lo que quieres" (funcional).

Entonces, en lugar de usar bucles, deberías aprender los algoritmos presentes en stl.


La indexación requiere una operación de mul adicional. Por ejemplo, para vector<int> v , el compilador convierte v[i] en &v + sizeof(int) * i .


La primera forma es eficiente solo si vector.size () es una operación rápida. Esto es cierto para los vectores, pero no para las listas, por ejemplo. Además, ¿qué planeas hacer dentro del cuerpo del bucle? Si planeas acceder a los elementos como en

T elem = some_vector[i];

entonces está asumiendo que el contenedor tiene el operator[](std::size_t) definido. De nuevo, esto es cierto para el vector pero no para otros contenedores.

El uso de iteradores te acerca a la independencia del contenedor. No está haciendo suposiciones acerca de la capacidad de acceso aleatorio o la operación rápida de size() , solo que el contenedor tiene capacidades de iterador.

Podría mejorar su código aún más mediante el uso de algoritmos estándar. Dependiendo de lo que esté tratando de lograr, puede elegir usar std::for_each() , std::transform() etc. Al usar un algoritmo estándar en lugar de un bucle explícito, está evitando reinventar la rueda. Es probable que su código sea más eficiente (dado que se elige el algoritmo correcto), correcto y reutilizable.


La segunda forma representa lo que estás haciendo con más precisión. En su ejemplo, no le importa el valor de i, en realidad, todo lo que desea es el siguiente elemento en el iterador.


Los iteradores STL están en su mayoría allí, de modo que los algoritmos STL como sort pueden ser independientes del contenedor.

Si solo desea recorrer todas las entradas de un vector, use el estilo de bucle de índice.

Es menos tipográfico y más fácil de analizar para la mayoría de los humanos. Sería bueno si C ++ tuviera un simple bucle de foreach sin pasarse por alto con la magia de la plantilla.

for( size_t i = 0; i < some_vector.size(); ++i ) { T& rT = some_vector[i]; // now do something with rT } ''


Nadie mencionó aún que una ventaja de los índices es que no se vuelven inválidos cuando se agrega a un contenedor contiguo como std::vector , por lo que puede agregar elementos al contenedor durante la iteración.

Esto también es posible con los iteradores, pero debe llamar a reserve() y, por lo tanto, debe saber cuántos elementos agregará.


No creo que haga mucha diferencia para un vector. Prefiero usar un índice, ya que lo considero más legible y puedo hacer un acceso aleatorio como saltar 6 elementos hacia adelante o saltar hacia atrás si es necesario.

También me gusta hacer una referencia al elemento dentro del bucle de esta manera para que no haya muchos corchetes alrededor del lugar:

for(size_t i = 0; i < myvector.size(); i++) { MyClass &item = myvector[i]; // Do stuff to "item". }

Usar un iterador puede ser bueno si crees que deberías reemplazar el vector con una lista en algún momento en el futuro y también parece más elegante para los fanáticos de STL pero no puedo pensar en ninguna otra razón.


No uso los iteradores por la misma razón por la que no me gustan las declaraciones de cada persona. Cuando se tienen múltiples bucles internos, es lo suficientemente difícil mantener un registro de las variables globales / miembros sin tener que recordar todos los valores locales y los nombres de iteradores también. Lo que encuentro útil es usar dos conjuntos de índices para diferentes ocasiones:

for(int i=0;i<anims.size();i++) for(int j=0;j<bones.size();j++) { int animIndex = i; int boneIndex = j; // in relatively short code I use indices i and j ... animation_matrices[i][j] ... // in long and complicated code I use indices animIndex and boneIndex ... animation_matrices[animIndex][boneIndex] ... }

Ni siquiera quiero abreviar cosas como "animación_matrices [i]" a algún "anim_matrix" -named-iterator aleatorio, por ejemplo, porque entonces no puede ver claramente de qué matriz se origina este valor.


Otra cosa buena sobre los iteradores es que es mejor que te permitan expresar (y hacer cumplir) tu preferencia de const. Este ejemplo garantiza que no alterará el vector en medio de su bucle:

for(std::vector<Foo>::const_iterator pos=foos.begin(); pos != foos.end(); ++pos) { // Foo & foo = *pos; // this won''t compile const Foo & foo = *pos; // this will compile }


Para independencia de contenedores


Porque es más orientado a objetos. Si está iterando con un índice, está asumiendo:

a) Que esos objetos estén ordenados.
b) Que esos objetos se pueden obtener mediante un índice.
c) que el incremento del índice afectará a cada elemento
d) que el índice comienza en cero

Con un iterador, estás diciendo "dame todo para poder trabajar con él" sin saber cuál es la implementación subyacente. (En Java, hay colecciones a las que no se puede acceder a través de un índice)

Además, con un iterador, no hay necesidad de preocuparse por salirse de los límites de la matriz.


Probablemente debería señalar que también puedes llamar

std::for_each(some_vector.begin(), some_vector.end(), &do_stuff);


Siempre uso el índice de matriz porque muchas de mis aplicaciones requieren algo como "mostrar imagen en miniatura". Así que escribí algo como esto:

some_vector[0].left=0; some_vector[0].top =0;<br> for (int i = 1; i < some_vector.size(); i++) { some_vector[i].left = some_vector[i-1].width + some_vector[i-1].left; if(i % 6 ==0) { some_vector[i].top = some_vector[i].top.height + some_vector[i].top; some_vector[i].left = 0; } }


Varios buenos puntos ya. Tengo algunos comentarios adicionales:

  1. Suponiendo que estamos hablando de la biblioteca estándar de C ++, "vector" implica un contenedor de acceso aleatorio que tiene las garantías de C-array (acceso aleatorio, diseño de memoria de contiguos, etc.). Si hubiera dicho ''some_container'', muchas de las respuestas anteriores habrían sido más precisas (independencia del contenedor, etc.).

  2. Para eliminar cualquier dependencia en la optimización del compilador, puede mover some_vector.size () fuera del bucle en el código indexado, de esta manera:

    const size_t numElems = some_vector.size(); for (size_t i = 0; i

  3. Always pre-increment iterators and treat post-increments as exceptional cases.

for (some_iterator = some_vector.begin(); some_iterator != some_vector.end(); ++some_iterator){ //do stuff }
  • Siempre pre-incrementa los iteradores y trata los incrementos posteriores como casos excepcionales.

  • para (some_iterator = some_vector.begin (); some_iterator! = some_vector.end (); ++ some_iterator) {// hacer cosas}

    Por lo tanto, suponiendo que sea un contenedor tipo std::vector<> indexable, no hay una buena razón para preferir uno sobre otro, pasando secuencialmente por el contenedor. Si tiene que consultar con frecuencia índices más antiguos o más nuevos, entonces la versión indexada es más apropiada.

    En general, es preferible utilizar los iteradores porque los algoritmos los utilizan y el comportamiento puede controlarse (y documentarse implícitamente) cambiando el tipo de iterador. Se pueden usar ubicaciones de matrices en lugar de iteradores, pero la diferencia sintáctica se mantendrá.


    Voy a ser el defensor de los demonios aquí, y no recomendaré a los iteradores. La razón principal por la cual, es todo el código fuente en el que he trabajado, desde el desarrollo de aplicaciones de escritorio hasta el desarrollo de juegos, no necesito usar iteradores. Todo el tiempo no han sido requeridos y, en segundo lugar, las suposiciones ocultas y el desorden del código y las pesadillas de depuración que obtienes con los iteradores los convierten en un excelente ejemplo para no usarlo en aplicaciones que requieran velocidad.

    Incluso desde un punto de vista de mantenimiento son un desastre. No es por causa de ellos, sino por todos los alias que ocurren detrás de la escena. ¿Cómo puedo saber que no ha implementado su propio vector virtual o lista de arreglos que hace algo completamente diferente a los estándares? ¿Sé qué tipo es actualmente durante el tiempo de ejecución? ¿Ha sobrecargado un operador? No tuve tiempo de verificar todo su código fuente. ¿Qué diablos sé qué versión de la STL estás usando?

    El siguiente problema que tienes con los iteradores es la abstracción con fugas, aunque hay numerosos sitios web que discuten esto en detalle con ellos.

    Lo siento, no he visto y todavía no he visto ningún punto en los iteradores. Si abstraen la lista o el vector lejos de ti, cuando en realidad ya debas saber qué vector o enumerar tus tratos, si no lo haces, simplemente te estarás preparando para algunas sesiones de depuración excelentes en el futuro.


    porque no está vinculando su código a la implementación particular de la lista some_vector. Si usa índices de matriz, tiene que ser alguna forma de matriz; Si usa iteradores, puede usar ese código en cualquier implementación de lista.


    • Si te gusta estar cerca del metal / no confíes en sus detalles de implementación, no uses iteradores.
    • Si cambia regularmente un tipo de colección por otro durante el desarrollo, use iteradores.
    • Si le resulta difícil recordar cómo iterar diferentes tipos de colecciones (quizás tenga varios tipos de varias fuentes externas diferentes en uso), use los iteradores para unificar los medios por los que recorre los elementos. Esto se aplica a decir, cambiar una lista enlazada con una lista de matriz.

    Realmente, eso es todo lo que hay que hacer. No es como si, en promedio, obtendrías más brevedad de cualquier manera, y si realmente la brevedad es tu objetivo, siempre puedes recurrir a las macros.