DMarlon Studio

Lección 13 · 13 de 20

Iteradores · C++

Recorra contenedores de C++ con iteradores: begin, end, rbegin, next, distance y erase en un std::list, con una ruta y una lista de reproducción.

C++ · Iteradores en DMarlon Studio: el código del ejemplo y su salida en la terminal

Un iterador señala un elemento de un contenedor: *it lo lee, ++it pasa al siguiente y it != route.end() comprueba si se ha llegado al final. Ojo: end() no es el último elemento, sino la posición que viene después. Los iteradores son lo que usa por dentro el for de rango y lo que reciben todos los algoritmos.

std::next(it) devuelve el iterador siguiente sin mover it; aquí sirve para saber si quedan ciudades y poner -> solo entre ellas. Con `rbegin()` y `rend()` se recorre al revés con el mismo código: el viaje de vuelta.

Los iteradores de std::vector son de acceso aleatorio: admiten aritmética, como route.begin() + 2. std::distance cuenta los pasos entre dos iteradores y stop->size() llama a un método del elemento señalado, igual que con un puntero.

En un `std::list` (una lista doblemente enlazada) insertar y borrar en medio es barato, pero borrar invalida el iterador del elemento borrado. Por eso erase(it) devuelve el siguiente y el bucle solo avanza con ++it cuando no borra. insert coloca «Jingle» delante de la posición indicada, la segunda. `cbegin()` y `cend()` dan iteradores const, que solo dejan leer.

Código · main.cpp

#include <iostream>#include <iterator>#include <list>#include <string>#include <vector>int main() {    // An iterator points to an element: *it reads it and ++it moves to the next.    std::vector<std::string> route = {"Madrid", "Zaragoza", "Lleida", "Barcelona"};    for (auto it = route.begin(); it != route.end(); ++it)        std::cout << *it << (std::next(it) != route.end() ? " -> " : "\n");    // Reverse iterators walk backwards: the trip home.    for (auto it = route.rbegin(); it != route.rend(); ++it)        std::cout << *it << (std::next(it) != route.rend() ? " -> " : "\n");    // Vector iterators allow arithmetic; distance counts the steps.    auto stop = route.begin() + 2;    std::cout << "Third stop: " << *stop << ", " << std::distance(route.begin(), stop)              << " steps from the start, " << stop->size() << " letters\n";    // In a list, erasing and inserting through an iterator is cheap.    std::list<std::string> playlist = {"Intro", "Ad", "Song A", "Ad", "Song B"};    for (auto it = playlist.begin(); it != playlist.end();) {        if (*it == "Ad") it = playlist.erase(it);      // erase returns the next one        else ++it;    }    playlist.insert(std::next(playlist.begin()), "Jingle");   // before the 2nd track    for (auto it = playlist.cbegin(); it != playlist.cend(); ++it)   // const: read only        std::cout << "[" << *it << "]";    std::cout << "\n";}

Salida · c++ -std=c++17 main.cpp -o main && ./main

Madrid -> Zaragoza -> Lleida -> Barcelona
Barcelona -> Lleida -> Zaragoza -> Madrid
Third stop: Lleida, 2 steps from the start, 6 letters
[Intro][Jingle][Song A][Song B]

Para recordar

  • *it lee el elemento, ++it avanza y end() está después del último.
  • rbegin() y rend() recorren al revés.
  • std::next, std::distance y la aritmética begin() + n mueven y miden.
  • erase(it) devuelve el iterador siguiente: úselo al borrar dentro de un bucle.
  • cbegin() y cend() dan iteradores de solo lectura.

Ejercicio

Use std::find para obtener un iterador a «Song A» en la lista de reproducción e inserte «Encore» justo después (pista: std::next). Escriba la lista final.