Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


5.1.2h  Manipulación de Iteradores

§1  Sinopsis

En la Librería Estándar existen dos funciones que permiten manipular iteradores: advance() y distance(). La primera permite desplazar un iterador, la segunda calcula la distancia entre dos iteradores relativos a un mismo contenedor. Sus descripciones están contenidas en la cabecera <iterator>.

§2  advance()

Esta función recibe dos argumentos, ambos por referencia: un iterador iter y un valor numérico n, que es el desplazamiento que queremos aplicar al iterador.  Como todos los algoritmos de la STL, es una plantilla que responde al siguiente prototipo:

void advance (InputIterator & iter, Distance & n);


En principio, su efecto es el mismo que aplicar al iterador un número equivalente de veces un desplazamiento unitario adecuado (iter++ o iter--). En el caso de iteradores de acceso aleatorio (RandomAccessIterator), el efecto es el mismo que hacer iter+n ( 5.1.2) y el tiempo de la operación es constante para cualquier desplazamiento.  Para el resto de iteradores el tiempo es función lineal del valor n del desplazamiento porque la función realiza el movimiento mediante una sucesión de pasos elementales.

La función puede aplicarse a cualquier iterador, pero el compilador no realiza ninguna comprobación de que la operación propuesta sea adecuada. Por ejemplo: si aplicamos un argumento n negativo a un operador de entrada (InputIterator) o salida (OutputIterator), se obtiene un error.  Solo pueden utilizarse argumentos n negativos con iteradores de acceso bidireccional o aleatorio.

§2.1 Ejemplo-1

#include <iostream>
#include <iterator>
using namespace std;

int main(void) {         // =================
  int A[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  int* aptr = A;
  cout << "Direccion inicial: " << aptr << endl;
  cout << "Valor inicial: " << *aptr << endl;
  advance(aptr, 5);
  cout << "Valor posicion I+5: " << *aptr << endl;
}

Salida:

Direccion inicial: 0065FDDC
Valor inicial: 0
Valor posicion I+5: 5

§2.1 Ejemplo-2

Una versión del anterior utilizando un contenedor estándar tipo vector.

#include <iostream>
#include <vector>
#include <iterator>
using namespace std;

int main(void) {         // ================
  int A[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  vector<int> Av(10);
  for (int i=0; i<10; i++) Av[i] = A[i];  // copiamos A en Av
  vector<int>::iterator vit1 = Av.begin();
  cout << "Direccion inicial: " << vit1 << endl;
  cout << "Valor inicial: " << *vit1 << endl;
  advance(vit1, 5);
  cout << "Valor posicion I+5: " << *vit1 << endl;
}

Salida:

Direccion inicial: 00672E18
Valor inicial: 0
Valor posicion I+5: 5

§3  distance()

Esta función devuelve el número de desplazamientos unitarios necesarios para mover un iterador desde un elemento de una secuencia a otro.  Existen dos versiones para esta función que responden a los siguientes prototipos:

template <class ForwardIterator>
  iterator_traits<ForwardIterator>::difference_type
  distance (ForwardIterator first,

            ForwardIterator last);


template <class ForwardIterator, class Distance>
  void distance (ForwardIterator first,

                 ForwardIterator last,
                 Distance& n);


La primera forma acepta dos iteradores como argumento y devuelve un entero (difference_type es tipo entero) que es el número de veces que hay que aplicar el operador suma unaria ++ a first para alcanzar la posición señalada por last.  Observe que el tipo devuelto (difference_type) es una especialización de la plantilla iterator_traits.

La segunda forma modifica el valor n suministrado como tercer argumento (que es pasado por referencia).  Esta variable debe ser iniciada adecuadamente antes de invocar la función [1].

Para que la función sea aplicable, es condición necesaria que el iterador last sea accesible ( 5.1.2) desde first.

§3.1  Ejemplo-3

#include <iostream>
#include <vector>
#include <iterator>
using namespace std;

int main(void) {     // ================
  int A[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  vector<int> Av(10);                            // M2:
  for (int i=0; i<10; i++) Av[i] = A[i];         // M3:
  vector<int>::iterator vit1 = Av.begin();
  vector<int>::iterator vit2 = Av.end();

  cout << "Valor de vit1: " << *vit1 << endl;
  cout << "Valor final: " << *(--vit2) << endl;  // M8:
  int distancia = distance(vit1, vit2);
  cout << "Distancia vit1, vit2: " << distancia << endl;
}

Salida:

Valor de vit1: 0
Valor final: 9
Distancia vit1, vit2: 9

Comentario:

En M2 se declara un contenedor Av de tipo vector capaz para 10 int; en M3 se asignan los valores de la matriz a los correspondientes miembros de Av. En M4 y M5 se definen sendos iteradores al comienzo y al final del contenedor. Las funciones begin() y end() utilizadas no son algoritmos genéricos, sino métodos de la clase vector.

Observe que en M8 no se calcula el valor final mediante la indirección del iterador vit2, ya que este elemento señala una posición past-the-end; para encontrar el último elemento del contenedor es preciso desplazar este iterador una posición hacia atrás.

  Inicio.


[1]  Esta segunda forma es adecuada si el compilador no soporta especialización parcial. Es una forma desaconsejada y a extinguir que se ha introducido para mantener cierta compatibilidad con compiladores antiguos.