Historia de la cuestión:
En C++, trabajar con memoria es fundamental, el lenguaje le brinda al programador un control total para mejorar la eficiencia. Inicialmente existían solo los conceptos de "stack" (pila) y "heap" (montón) como áreas de asignación de memoria automática y dinámica.
Problema:
La elección del área donde se coloca una variable determina su tiempo de vida, disponibilidad, velocidad de asignación y liberación de memoria, así como los riesgos (fugas, corrupción de la pila, fragmentación).
Solución:
La asignación en la pila se utiliza para variables locales con un tiempo de vida predecible. La asignación en el montón se utiliza para objetos que requieren un tiempo de vida dinámico o un gran volumen de memoria. Se recomienda minimizar la gestión manual del montón, prefiriendo la pila y utilizando punteros inteligentes para trabajar con la memoria dinámica.
Ejemplo de código:
// Asignación en la pila int a = 5; // Asignación en el montón int* b = new int(10); // Trabajo con un puntero inteligente #include <memory> auto ptr = std::make_unique<int>(15);
¿Qué sucederá si devolvemos un puntero a una variable local desde una función?
Ocurrirá un comportamiento indefinido: después de salir de la función, la memoria "se libera" (en realidad, la pila no se limpia, pero los datos pueden ser sobrescritos).
Ejemplo de un mal código:
int* foo() { int a = 42; return &a; // ¡incorrecto! }
¿Puede la memoria asignada en la pila tener fugas?
No, la memoria de la pila siempre se libera automáticamente al salir del ámbito — solo ocurre lo que se conoce como un desbordamiento de pila (stack overflow), pero no una fuga.
¿Es suficiente siempre usar delete para liberar la memoria dinámica?
No, con mucha más frecuencia se utilizan punteros inteligentes (std::unique_ptr, std::shared_ptr) para evitar deletes olvidados y eliminaciones dobles.
Caso negativo:
El desarrollador usó new para todos los objetos temporales, olvidó liberarlos — con el tiempo, en aplicaciones grandes aparecieron fugas de memoria.
Ventajas: al principio rápido y conveniente Desventajas: programas inestables, aumento de memoria, caídas
Caso positivo:
Uso de variables locales y punteros inteligentes para objetos temporales y auxiliares. No hay delete explícito, todo se libera automáticamente.
Ventajas: ausencia de fugas, confiabilidad Desventajas: se requiere entender los enfoques modernos para trabajar con memoria