C++ vector vs array: ¿cuál deberías usar?
Primero la respuesta corta, luego los detalles que sí importan en una entrevista y en código real.
La respuesta en 10 segundos
Por defecto, std::vector. Usa un array estilo C solo cuando el tamaño fijo forme parte del problema — y aun así prefiere std::array antes que el array crudo. Todo lo de abajo explica el porqué, porque «usa vector y ya» no sobrevive a la primera pregunta de seguimiento.
Tres contenedores, una misma idea
| Array estilo C | std::array | std::vector | |
|---|---|---|---|
| Tamaño | Fijo en tiempo de compilación | Fijo en tiempo de compilación | Crece y se encoge en ejecución |
| ¿Dónde vive? | Donde lo declares (en la pila si es local) | Donde lo declares | Los datos en el heap; el objeto puede vivir en cualquier parte |
| ¿Sabe su longitud? | No — la llevas tú aparte | Sí — .size() | Sí — .size() |
| ¿Se puede copiar? | No (decae a puntero) | Sí | Sí |
| Pasarlo a una función | Incómodo (se convierte en puntero y se pierde el tamaño) | Limpio | Limpio |
| Comprobación de límites | Ninguna | .at() comprueba | .at() comprueba, [] no |
Cómo se ve cada uno
#include <array>
#include <vector>
int main() {
int raw[5] = {1, 2, 3, 4, 5}; // estilo C: el tamaño es parte del tipo
std::array<int, 5> fijo = {1, 2, 3, 4, 5}; // tamaño fijo, pero es un tipo de verdad
std::vector<int> crece = {1, 2, 3}; // redimensionable
crece.push_back(4); // ahora contiene 1 2 3 4
return 0;
}
Nota: nuestro editor en el navegador cubre hoy el núcleo para principiantes (iostream, cmath, cstdio…), así que fragmentos como este pruébalos en tu compilador de escritorio — o en el editor cuando llegue el soporte completo de contenedores.
Por qué vector gana por defecto
- El tamaño se decide en ejecución. Casi ningún dato real tiene una longitud conocida al compilar: las líneas de un archivo, lo que escribe el usuario, los mensajes de red. Un vector se redimensiona; un array no.
- Recuerda su longitud. Pasar un array crudo a una función lo convierte en un puntero sin avisar — la fuente clásica de bugs y desbordamientos. Un vector lleva
.size()a todas partes. - Igual de rápido. El almacenamiento de un vector es un único bloque contiguo de memoria, exactamente como un array. Recorrerlo cuesta lo mismo una vez pasado el crecimiento inicial. Si sabes el tamaño final, llama antes a
reserve(n)y no queda casi nada que pagar. - Encaja con todo — bucles
forpor rango, algoritmos comostd::sorty el resto de la biblioteca estándar.
Cuándo un array (de tamaño fijo) es de verdad mejor
- El tamaño viene fijado por el problema: los días de la semana, un tablero de ajedrez (8×8), los tres componentes de un RGB.
- Estás en un bucle crítico sobre un sistema embebido y quieres cero uso del heap —
std::arraynunca reserva memoria dinámica. - Necesitas el objeto en la pila y sabes que es pequeño.
Preguntas de seguimiento que conviene tener preparadas
- «¿Cómo crece un vector?» Al llenarse reserva un bloque mayor (habitualmente ~1,5× o 2×) y mueve los elementos — por eso
push_backrepetido sigue siendo O(1) amortizado. - «¿Qué es
vector<bool>?» Una pregunta trampa: es una especialización que empaqueta bits y no se comporta como un vector normal de valores. - «¿Diferencia entre
size()ycapacity()?»size()= elementos en uso;capacity()= huecos reservados antes del siguiente crecimiento. - «¿Un vector puede invalidar punteros?» Sí — cualquier crecimiento o
insert/erasepuede mover el almacenamiento. No guardes punteros ni referencias al interior de un vector y luego lo modifiques.
Regla práctica
Escribe std::vector hasta que tengas una razón medida para no hacerlo. ¿Tamaño fijo por naturaleza? Usa std::array. Los arrays crudos de C son para hablar con código C y para trabajo embebido con memoria ajustada — y aun ahí, envueltos.