Café y Código
📦 STL DinámicaEvolución del Inventario

std::vector en C++: La Colección Dinámica Moderna

En la lección anterior descubrimos que los arreglos fijos requieren controlar manualmente la capacidad (inventario[9]), contar los elementos ocupados (cantidadInventario) y desplazar la memoria a mano al borrar. Con std::vector todo eso queda resuelto de forma automática, segura y con memoria dinámica.

1. La Gran Evolución: De Arreglo Fijo a std::vector

Para usar vectores en C++ debemos incluir la cabecera estándar #include <vector>. Observa la dramática simplificación:

Antes: Arreglo Estáticostring inventario[9];
int cantidadInventario = 6;
  • Capacidad fija en tiempo de compilación.
  • No puede crecer más allá de 9 casillas.
  • El programador debe gestionar el contador de ocupación.
Ahora: std::vector Dinámicovector<string> inventario;
  • Crece y decrece automáticamente en tiempo de ejecución.
  • DesaparececantidadInventario: se consulta con inventario.size().
  • Reorganiza y administra la memoria interna por ti.

Podemos inicializar el vector con los 9 objetos iniciales o dejarlo vacío:

Declaración e inicialización de un vector
CPP
1#include <iostream>
2#include <string>
3#include <vector>
4
5using namespace std;
6
7int main() {
8 // Inicialización de un vector con 9 elementos
9 vector<string> inventario = {
10 "Espada", "Pico", "Hacha", "Pan", "Madera",
11 "Piedra", "Diamante", "Antorcha", "Arco"
12 };
13
14 cout << "Cantidad de objetos en el inventario: " << inventario.size() << endl; // 9
15
16 return 0;
17}

2. Inserción Dinámica con push_back(): Superando el Límite de 9

¿Qué ocurre si el jugador recoge un décimo objeto (ej. "Manzana")? En el arreglo fijo recibíamos un error de desbordamiento. Con vector, simplemente llamamos al método push_back():

🎮 Inventario Expandido (10 casillas)inventario.push_back("Manzana");
Espada[0]
Pico[1]
Hacha[2]
Pan[3]
Madera[4]
Piedra[5]
Diamante[6]
Antorcha[7]
Arco[8]
🍎 Manzana[9]
Uso de push_back()
CPP
1// Agregar un elemento al final del vector
2inventario.push_back("Manzana");
3
4cout << "Nuevo tamaño: " << inventario.size() << endl; // 10
5cout << "Ultimo objeto: " << inventario.back() << endl; // Manzana

3. Eliminación Automática con erase()

En arreglos tradicionales teníamos que programar un bucle manual para mover todos los elementos de la derecha una posición hacia la izquierda. Con std::vector, el método .erase() se encarga de todo el desplazamiento en una sola línea:

❌ Antes (Arreglo con bucle for):
for (int i = pos; i < n - 1; i++) {
    inventario[i] = inventario[i + 1];
}
n--;
✅ Ahora (std::vector):
// Borra el elemento en la posición y reorganiza todo
inventario.erase(inventario.begin() + posicion);
💡 ¿Qué significa inventario.begin()?
Es un iterador que apunta al inicio del vector (índice 0). Al sumarle+ 2, apunta exactamente al tercer elemento (índice 2) para que erase lo elimine.

4. Tabla de Métodos Esenciales de std::vector

Estas son las operaciones que utilizarás en el 99% de tus programas en C++:

MétodoDescripciónEjemplo
.size()Retorna la cantidad actual de elementos en el vector.int total = inventario.size();
.empty()Retorna true si el vector no tiene elementos (tamaño 0).if (inventario.empty()) cout << "Vacio";
.push_back(val)Inserta un elemento al final de la colección.inventario.push_back("Diamante");
.pop_back()Elimina el último elemento del vector.inventario.pop_back();
.erase(pos)Elimina el elemento en la posición dada y ajusta los índices.inventario.erase(inventario.begin() + 1);
.clear()Elimina todos los elementos, dejando el vector con tamaño 0.inventario.clear();
.front() / .back()Devuelve el primer o el último elemento respectivamente.cout << inventario.front();
.at(pos)Acceso con validación de límites (lanza excepción si está fuera de rango).string item = inventario.at(2);

5. Modularización: Funciones con vector<string>&

Al pasar vectores a funciones en C++, existen dos reglas de oro para maximizar el rendimiento y evitar copias costosas:

1. Solo Lectura: const vector<string>&

Se pasa por referencia constante. Evita duplicar el vector en memoria y garantiza que la función no modifique los datos por error (ideal para mostrarInventario y buscarObjeto).

2. Modificación: vector<string>&

Se pasa por referencia mutable. Permite que funciones como agregarObjeto, eliminarObjeto o modificarObjeto alteren directamente el vector del main.

Funciones modulares con std::vector
CPP
1// Función de solo lectura (const &): no copia el vector y no lo modifica
2void mostrarInventario(const vector<string>& inventario) {
3 if (inventario.empty()) {
4 cout << "\n[!] El inventario esta vacio.\n";
5 return;
6 }
7
8 cout << "\n=== INVENTARIO MINECRAFT (" << inventario.size() << " objetos) ===\n";
9 for (size_t i = 0; i < inventario.size(); i++) {
10 cout << "[" << i << "] " << inventario[i] << "\n";
11 }
12 cout << "=======================================\n";
13}
14
15// Función que modifica el vector (& mutable)
16void agregarObjeto(vector<string>& inventario) {
17 string nuevo;
18 cout << "Nombre del nuevo objeto a recolectar: ";
19 cin >> nuevo;
20
21 inventario.push_back(nuevo);
22 cout << "[OK] ¡" << nuevo << " agregado al final del inventario!\n";
23}
24
25void eliminarObjeto(vector<string>& inventario) {
26 if (inventario.empty()) {
27 cout << "\n[!] No hay objetos para eliminar.\n";
28 return;
29 }
30
31 int pos;
32 cout << "Indice a eliminar (0 a " << inventario.size() - 1 << "): ";
33 cin >> pos;
34
35 if (pos < 0 || pos >= static_cast<int>(inventario.size())) {
36 cout << "[X] Indice fuera de rango.\n";
37 return;
38 }
39
40 cout << "[OK] " << inventario[pos] << " eliminado con exito.\n";
41 inventario.erase(inventario.begin() + pos);
42}
43
44// Función que busca y devuelve el índice (int) o -1 si no existe
45int buscarObjeto(const vector<string>& inventario, const string& itemBuscado) {
46 for (size_t i = 0; i < inventario.size(); i++) {
47 if (inventario[i] == itemBuscado) {
48 return static_cast<int>(i);
49 }
50 }
51 return -1;
52}

6. Programa Completo: CRUD de Inventario Dinámico en C++

Este es el código completo con menú interactivo utilizando std::vector. Cópialo y pruébalo en tu compilador:

CRUD Completo de Inventario con std::vector en C++
CPP
1#include <iostream>
2#include <string>
3#include <vector>
4
5using namespace std;
6
7// Prototipos de funciones
8void mostrarInventario(const vector<string>& inventario);
9void agregarObjeto(vector<string>& inventario);
10void modificarObjeto(vector<string>& inventario);
11void eliminarObjeto(vector<string>& inventario);
12int buscarObjeto(const vector<string>& inventario, const string& item);
13
14int main() {
15 // Vector con 6 objetos iniciales
16 vector<string> inventario = {
17 "Espada", "Pico", "Madera", "Pan", "Piedra", "Arco"
18 };
19
20 int opcion = 0;
21
22 do {
23 cout << "\n========================================\n";
24 cout << " SISTEMA DE INVENTARIO DINAMICO (STL) \n";
25 cout << "========================================\n";
26 cout << "1. Mostrar inventario\n";
27 cout << "2. Agregar objeto (push_back)\n";
28 cout << "3. Modificar objeto\n";
29 cout << "4. Eliminar objeto (erase)\n";
30 cout << "5. Buscar objeto\n";
31 cout << "6. Vaciar inventario completo (clear)\n";
32 cout << "7. Salir\n";
33 cout << "Seleccione una opcion (1-7): ";
34 cin >> opcion;
35
36 switch (opcion) {
37 case 1:
38 mostrarInventario(inventario);
39 break;
40 case 2:
41 agregarObjeto(inventario);
42 break;
43 case 3:
44 modificarObjeto(inventario);
45 break;
46 case 4:
47 eliminarObjeto(inventario);
48 break;
49 case 5: {
50 string item;
51 cout << "Nombre del objeto a buscar: ";
52 cin >> item;
53 int pos = buscarObjeto(inventario, item);
54 if (pos != -1) {
55 cout << "[!] Encontrado en la posicion [" << pos << "].\n";
56 } else {
57 cout << "[X] El objeto no esta en el inventario.\n";
58 }
59 break;
60 }
61 case 6: {
62 char confirmar;
63 cout << "¿Seguro que desea vaciar todo el inventario? (s/n): ";
64 cin >> confirmar;
65 if (confirmar == 's' || confirmar == 'S') {
66 inventario.clear();
67 cout << "[OK] Inventario vaciado por completo.\n";
68 }
69 break;
70 }
71 case 7:
72 cout << "Cerrando inventario... ¡Buen viaje aventurero!\n";
73 break;
74 default:
75 cout << "[X] Opcion invalida. Intente de nuevo.\n";
76 }
77 } while (opcion != 7);
78
79 return 0;
80}
81
82void mostrarInventario(const vector<string>& inventario) {
83 if (inventario.empty()) {
84 cout << "\n[!] El inventario esta vacio.\n";
85 return;
86 }
87 cout << "\n=== INVENTARIO ACTUAL (" << inventario.size() << " elementos) ===\n";
88 for (size_t i = 0; i < inventario.size(); i++) {
89 cout << " [" << i << "] " << inventario[i] << "\n";
90 }
91 cout << "========================================\n";
92}
93
94void agregarObjeto(vector<string>& inventario) {
95 string nuevo;
96 cout << "Nombre del objeto a agregar: ";
97 cin >> nuevo;
98
99 inventario.push_back(nuevo);
100 cout << "[OK] " << nuevo << " guardado en la posicion [" << inventario.size() - 1 << "].\n";
101}
102
103void modificarObjeto(vector<string>& inventario) {
104 if (inventario.empty()) {
105 cout << "\n[!] El inventario esta vacio.\n";
106 return;
107 }
108 int pos;
109 cout << "Indice a modificar (0 a " << inventario.size() - 1 << "): ";
110 cin >> pos;
111
112 if (pos < 0 || pos >= static_cast<int>(inventario.size())) {
113 cout << "[X] Indice fuera de rango.\n";
114 return;
115 }
116 cout << "Reemplazando [" << inventario[pos] << "]. Nuevo nombre: ";
117 cin >> inventario[pos];
118 cout << "[OK] Posicion [" << pos << "] actualizada.\n";
119}
120
121void eliminarObjeto(vector<string>& inventario) {
122 if (inventario.empty()) {
123 cout << "\n[!] El inventario esta vacio.\n";
124 return;
125 }
126 int pos;
127 cout << "Indice a eliminar (0 a " << inventario.size() - 1 << "): ";
128 cin >> pos;
129
130 if (pos < 0 || pos >= static_cast<int>(inventario.size())) {
131 cout << "[X] Indice invalido.\n";
132 return;
133 }
134 cout << "[OK] " << inventario[pos] << " eliminado.\n";
135 inventario.erase(inventario.begin() + pos);
136}
137
138int buscarObjeto(const vector<string>& inventario, const string& item) {
139 for (size_t i = 0; i < inventario.size(); i++) {
140 if (inventario[i] == item) return static_cast<int>(i);
141 }
142 return -1;
143}

7. Cuadro Comparativo Definitivo: Arreglo vs. std::vector

Usa esta guía rápida para decidir cuándo conviene usar un arreglo tradicional o un std::vector:

AspectoArreglo Estático (T[])std::vector<T>
TamañoFijo en compilación (ej. string inv[9]).Dinámico: crece y se achica según la necesidad.
Ubicación de MemoriaStack (rápido, pero limitado en tamaño).Heap (memoria dinámica administrada automáticamente).
Inserción al finalManual: inv[cnt++] = x; (con riesgo de overflow).Automática: inv.push_back(x);
Eliminación en medioRequiere bucle manual de desplazamiento.Directa: inv.erase(inv.begin() + i);
Saber cuántos hayRequiere variable adicional (cantidadInventario).Directo con inv.size().
RecomendaciónPara tamaños pequeños y estrictamente constantes conocidos de antemano.La opción estándar por defecto en C++ moderno.

Dato curioso: C++ apareció en 1985; Bjarne Stroustrup en Bell Labs. Wikipedia

Ko-fi
Donaciones
Apoyá cafeycodigo con un café en Ko-fi. Colaboradores: insignia, muro y zona exclusiva.