Eliminación de un elemento de un vector por índice: anatomía de std::vector::erase

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Cómo borrar un elemento de std::vector por índice: mirando bajo el capó

\n\n

¡Hola, colega! Si alguna vez has programado en C++ y has trabajado con arreglos dinámicos, seguro te has encontrado con la pregunta: "How do I erase an element from std::vector<> by index?" — esta es una de las consultas más populares en Stack Overflow, y con razón. A primera vista, la tarea parece trivial: llamas a erase y listo. Pero, ¿qué sucede realmente en la memoria? ¿Por qué eliminar un elemento del medio del vector es costoso? ¿Y cómo evitar pisar el rastrillo con los iteradores?

\n\n

En este artículo no solo mostraremos cómo escribir v.erase(v.begin() + index). Analizaremos cómo funciona esta operación bajo el capó, qué estructuras de datos están involucradas y cómo elegir la forma óptima de eliminar. ¡Vamos allá!

\n\n

1. std::vector: ¿qué clase de bestia es esta?

\n\n

Antes de eliminar, recordemos cómo está estructurado std::vector. Es un arreglo dinámico que almacena elementos en un área de memoria contigua. Tiene tres punteros (o iteradores) clave:

\n
    \n
  • begin — el inicio de la memoria asignada;
  • \n
  • end — el final de la memoria ocupada (después del último elemento);
  • \n
  • capacity — el final de la memoria asignada (el límite hasta el cual puede crecer sin reasignación).
  • \n
\n\n

Visualmente se ve así:

\n
[0] [1] [2] [3] [4] ... [capacity-1]\n ^                        ^\n begin                   end\n
\n\n

Cuando eliminas un elemento del medio, el vector no simplemente lo "descarta" — físicamente desplaza todos los elementos siguientes hacia la izquierda. Este es el principal "dolor" de la operación erase.

\n\n

2. Eliminación por índice: sintaxis básica

\n\n

La forma más sencilla de eliminar un elemento por índice es usar el método erase con un iterador:

\n\n
#include <vector>\n#include <iostream>\n\nint main() {\n    std::vector<int> v = {10, 20, 30, 40, 50};\n    int index = 2; // queremos eliminar el tercer elemento (30)\n\n    // Verificamos que el índice esté dentro del rango\n    if (index < v.size()) {\n        v.erase(v.begin() + index);\n    }\n\n    for (int x : v) std::cout << x << " ";\n    // Salida: 10 20 40 50\n    return 0;\n}\n
\n\n

Simple, ¿verdad? Pero, ¿qué pasa si necesitas eliminar varios elementos consecutivos? Para eso existe la sobrecarga erase(first, last):

\n\n
v.erase(v.begin() + 1, v.begin() + 3); // eliminará los elementos con índices 1 y 2\n
\n\n

3. ¿Y qué hay bajo el capó? Análisis detallado

\n\n

Ahora viene lo interesante. Cuando llamas a v.erase(iterator), internamente sucede lo siguiente:

\n\n
    \n
  1. Verificación del iterador (en modo debug) — nos aseguramos de que sea válido y apunte a un elemento del vector.
  2. \n
  3. Desplazamiento de elementos — todos los elementos que están después del eliminado se copian (o mueven, si el tipo soporta move semantics) una posición hacia la izquierda.
  4. \n
  5. Reducción del tamaño — el contador interno size se reduce en 1.
  6. \n
  7. Destructor — para el elemento "final" (que ahora está duplicado) se llama al destructor (si el tipo no es trivial).
  8. \n
\n\n

Veamos una implementación simplificada (pseudocódigo):

\n\n
template<typename T>\ntypename std::vector<T>::iterator\nvector<T>::erase(iterator pos) {\n    // 1. Desplazamos todos los elementos después de pos una posición a la izquierda\n    for (auto it = pos; it != end() - 1; ++it) {\n        *it = std::move(*(it + 1));\n    }\n    // 2. Reducimos el tamaño\n    --size;\n    // 3. Llamamos al destructor para el último elemento\n    allocator.destroy(end()); // end() ahora apunta al que era el último elemento\n    return pos; // devolvemos un iterador al elemento siguiente al eliminado\n}\n
\n\n

Observa el std::move — el C++ moderno intenta evitar

Blogs

Book Recommendations