ProgramaciónDesarrollador C++

¿Qué son los iteradores en C++ STL, qué tipos existen y qué matices de su uso deben conocerse al programar?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

Los iteradores son objetos que permiten referirse a los elementos de los contenedores STL de manera similar a los punteros. Proporcionan un método unificado de acceso a los elementos de cualquier contenedor (vector, lista, mapa, etc.). Los iteradores vienen en varios tipos:

  • InputIterator — para leer secuencias hacia adelante.
  • OutputIterator — para escribir valores en secuencias.
  • ForwardIterator — para leer y escribir hacia adelante (vive más tiempo que OutputIterator).
  • BidirectionalIterator — permite moverse tanto hacia adelante como hacia atrás.
  • RandomAccessIterator — soporta acceso aleatorio (por ejemplo, std::vector::iterator).

Se debe prestar especial atención a la vida de los iteradores:

  • Los iteradores de los contenedores pueden invalidarse al cambiar el contenedor. Por ejemplo, insertar elementos en un vector puede hacer que los iteradores antiguos se invaliden.
  • Diferentes contenedores manejan de manera diferente el ciclo de vida de los iteradores. En std::list, insertar o eliminar no invalida otros iteradores, mientras que en std::vector — casi siempre los invalida.

Ejemplo:

std::vector<int> v = {1,2,3,4,5}; for (auto it = v.begin(); it != v.end(); ++it) { if (*it == 3) { // Eliminamos el elemento con valor 3 it = v.erase(it); // erase devuelve el iterador al siguiente elemento --it; // ajustar el iterador si es necesario } }

Pregunta capciosa

Pregunta: ¿Con la llamada a std::vector::insert se invalidan los iteradores?
Respuesta común: No, solo al agregar fuera del rango final.
Respuesta correcta: Todos los iteradores y referencias que son iguales o siguen a la posición de inserción se invalidan si la capacidad del contenedor aumenta. Si la capacidad es suficiente, solo se invalidan los iteradores en el rango después del punto de inserción.

Ejemplo:

std::vector<int> v = {1,2,3}; auto it = v.begin() + 1; v.insert(v.begin(), 0); // it aquí puede estar invalidado!

Ejemplos de errores reales por desconocer los matices del tema


Historia: En un proyecto, se utilizaron punteros para iterar sobre std::vector y, después de un push_back, la iteración continuaba sobre punteros invalidados, lo que causando un fallo en la aplicación.



Historia: Un desarrollador eliminaba elementos de std::list usando erase en un bucle for(auto it : list), sin usar el iterador devuelto por erase, como resultado, la iteración saltaba elementos y no se eliminaban todos los necesarios.



Historia: En el código se utilizaba std::map, y después de erase por clave, el iterador permanecía vinculado al elemento eliminado (comportamiento indefinido) — esto provocó fallos aleatorios en posteriores accesos.