En C++, los datos y variables se almacenan en diferentes áreas de memoria con propósitos específicos. Comprender estas áreas es fundamental para escribir código eficiente y seguro.
Es un área gestionada automáticamente por el compilador y el sistema en tiempo de ejecución. Aquí se almacenan:
- Variables locales de funciones
- Parámetros de funciones
- Información de control (direcciones de retorno)
Características:
- Gestión automática: al entrar en una función, se reservan las variables; al salir, se liberan.
- Muy rápida, debido a su gestión estructurada y proximidad al procesador.
- Tamaño limitado: abusar de la recursión o declarar estructuras grandes puede causar stack overflow.
#include <iostream>
void funcion() {
int x = 5; // Variable local en el stack
std::cout << "x = " << x << "\n";
} // al salir de la función, x se libera automáticamente
int main() {
funcion();
return 0;
}Es un área de memoria cuya gestión depende del programador. Permite reservar bloques en tiempo de ejecución cuya duración no está ligada al alcance de una función.
Características:
- Vida útil extendida más allá del bloque en el que se creó.
- Flexibilidad: el tamaño puede definirse en tiempo de ejecución.
- Requiere gestión manual: si no se libera, aparecen fugas de memoria.
- Más lenta que el stack, por la complejidad de asignación.
En C++ tradicional, se utilizan los operadores:
new: reserva memoria en el heap y devuelve un puntero.delete: libera memoria previamente asignada connew.- Para arrays:
new[]ydelete[].
#include <iostream>
int main() {
int* ptr = new int; // Reserva espacio para un entero en el heap
*ptr = 42; // Uso de la memoria
std::cout << "Valor: " << *ptr << "\n";
delete ptr; // Liberación manual
return 0;
}#include <iostream>
int main() {
int* array = new int[100]; // Reserva un array de 100 enteros en el heap
array[0] = 10; // Uso del array
array[99] = 50;
std::cout << "Primer elemento: " << array[0]
<< ", Último: " << array[99] << "\n";
delete[] array; // Liberación de memoria del array
return 0;
}Aquí tienes la sección reescrita sin iconos, con programas completos y comentarios explicativos en un estilo formal y claro:
Cuando se gestiona memoria manualmente con new y delete, pueden producirse errores graves que afectan la estabilidad del programa. A continuación se muestran los errores más comunes y sus implicaciones.
Una fuga de memoria ocurre cuando se reserva memoria dinámica y se pierde la referencia al bloque asignado sin haberlo liberado. El espacio de memoria reservado no se puede recuperar, lo que provoca consumo innecesario de recursos.
#include <iostream>
int main() {
int* ptr = new int(10); // reserva dinámica
// Error: se pierde la referencia al bloque reservado
ptr = nullptr;
// El bloque original sigue existiendo en memoria, pero ya no es accesible
std::cout << "Fuga de memoria: el entero reservado nunca se libera.\n";
return 0;
}Liberar la misma dirección de memoria más de una vez produce comportamiento indefinido. El sistema intenta liberar un bloque ya liberado, lo que puede causar un fallo de segmentación o errores impredecibles.
#include <iostream>
int main() {
int* ptr = new int(10); // reserva memoria
delete ptr; // primera liberación
// Error: segunda liberación del mismo bloque
delete ptr; // comportamiento indefinido
std::cout << "Este mensaje podría no mostrarse correctamente.\n";
return 0;
}Un puntero colgante (dangling pointer) es un puntero que sigue apuntando a una dirección de memoria que ya fue liberada. Cualquier intento de acceso o modificación de esa memoria es un error grave y produce comportamiento indefinido.
#include <iostream>
int main() {
int* ptr = new int(10);
delete ptr; // el bloque ya no es válido
// Error: acceso a memoria liberada
*ptr = 5; // comportamiento indefinido
std::cout << "Valor: " << *ptr << "\n"; // lectura inválida
return 0;
}