Pregunta

Esta pregunta ya tiene respuesta aquí:

En la biblioteca STL, algunos contenedores tienen iteradores y comúnmente se sostiene que son una forma superior de iterar a través de estos contenedores en lugar de simples bucles for, p.

for ( int i=0; i < vecVector.size(); i++ )
{

..

}

¿Alguien puede decirme por qué y en qué casos debería usar iteradores y en qué casos el fragmento de código anterior, por favor?

¿Fue útil?

Solución

Tenga en cuenta que la implementación habitual de vector no utilizará un " int " como el tipo de índice / tamaño. Por lo tanto, su código al menos provocará advertencias del compilador.

Genericidad

Los iteradores aumentan el carácter genérico de su código.

Por ejemplo:

typedef std::vector<int> Container ;

void doSomething(Container & p_aC)
{
    for(Container::iterator it = p_aC.begin(), itEnd = p_aC.end(); it != itEnd; ++it)
    {
       int & i = *it ; // i is now a reference to the value iterated
       // do something with "i"
    }
}

Ahora, imaginemos que cambia el vector a una lista (porque en su caso, la lista ahora es mejor). Solo necesita cambiar la declaración typedef y volver a compilar el código.

Si hubieras utilizado código basado en índices, habría que volver a escribirlo.

Acceso

El iterador debe verse como una especie de superpuntero. & Quot; puntos & Quot; al valor (o, en el caso de los mapas, al par de clave / valor).

Pero tiene métodos para pasar al siguiente elemento en el contenedor. O lo anterior. Algunos contenedores ofrecen incluso acceso aleatorio (el vector y el deque).

Algoritmos

La mayoría de los algoritmos STL funcionan en iteradores o en rangos de iteradores (nuevamente, debido a su carácter genérico). No podrá utilizar un índice, aquí.

Otros consejos

El uso de iteradores permite que su código sea independiente de la implementación de su contenedor. Si el acceso aleatorio para su contenedor es barato, no hay mucha diferencia en cuanto al rendimiento.

Pero en muchos casos no sabrás si ese es el caso. Si intenta utilizar su método en una lista vinculada, por ejemplo, con subíndice, el contenedor tendrá que recorrer la lista en cada iteración para encontrar su elemento.

Entonces, a menos que sepa con certeza que el acceso aleatorio a su contenedor es barato, use un iterador.

Si usa iteradores como argumentos para su función, puede desacoplarla del tipo de " container " usado. Por ejemplo, puede dirigir los resultados de una función a la salida de la consola en lugar de un vector (ejemplo a continuación). Este truco puede ser enormemente poderoso para reducir el acoplamiento entre tus clases. Las clases sueltas son mucho más fáciles de probar.

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

template <typename InputIterator, typename OutputIterator>
void AddOne(InputIterator begin, InputIterator end, OutputIterator dest)
{
    while (begin != end)
    {
        *dest = *begin + 1;
        ++dest;
        ++begin;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector<int> data;
    data.push_back(1);
    data.push_back(2);
    data.push_back(3);

    // Compute intermediate results vector and dump to console
    vector<int> results;
    AddOne(data.begin(), data.end(), back_inserter(results));
    copy(results.begin(), results.end(), ostream_iterator<int>(cout, " "));
    cout << endl;

    // Compute results and send directly to console, no intermediate vector required
    AddOne(data.begin(), data.end(), ostream_iterator<int>(cout, " "));
    cout << endl;

    return 0;
}

En su ejemplo, la llamada a vecVector.size () es menos eficiente que usar un iterador. El iterador esencialmente lo encapsula de tener que preocuparse por el tamaño del contenedor en el que se itera. Además, el iterador no necesariamente tiene que ir en orden secuencial. Simplemente tiene que responder a una llamada .next de la forma que considere conveniente.

Bueno, para empezar, lo anterior ya no funcionará si convierte ese vector en una lista.

Los iteradores le permiten crear plantillas de funciones que no necesitan conocer el tipo de contenedor en el que trabajan. Incluso puede hacer lo siguiente:

#include <algorithm>

void printvalue(double s)
{
    // Do something with s
}

int _tmain(int argc, _TCHAR* argv[])
{
    double s[20] = {0};

    std::for_each(s, s+20, printvalue);

    return 0;
}

Esto se debe a que un puntero estándar también es un iterador válido para for_each.

Dave

El iterador es principalmente un nivel superior de abstracción.

Su fragmento supone que el contenedor se puede indexar.Esto es cierto para std::vector<> y algunos otros contenedores, por ejemplo, matrices sin formato.

Pero std::set<> carece de indexación por completo y el operador de índice de std::map<> insertará cualquier argumento que se le proporcione en el mapa, no el comportamiento esperado en su for-bucle.

Además, los problemas de desempeño sólo son problemas cuando se miden y se demuestran.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top