Memoria Stack vs Heap
Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 12 de 104.
Los programas de C++ utilizan dos regiones de memoria principales: la pila (stack) y el montículo (heap). Comprender dónde residen sus objetos es crucial para escribir código eficiente y libre de errores.
La pila (stack) es memoria rápida y automática. Las variables declaradas dentro de las funciones residen aquí y se destruyen automáticamente cuando salen de su ámbito (scope).
void example() {
int x = 10; // Asignación en el stack
Player player; // Asignación en el stack - destruido automáticamente
} // x y player se destruyen aquíEl heap es una memoria más grande pero más lenta que se gestiona manualmente. Los objetos en el heap persisten hasta que los eliminas explícitamente.
void example() {
Player* player = new Player(); // Asignación en el heap
// player existe hasta que se elimine
delete player; // Se requiere limpieza manual
}Diferencias clave:
| Stack | Heap |
|---|---|
| Asignación rápida | Asignación más lenta |
| Tamaño limitado | Gran capacidad |
| Limpieza automática | Requiere limpieza manual |
| Objetos de tamaño fijo | Objetos de tamaño dinámico |
Utilice la asignación en pila para objetos pequeños y de vida corta. Utilice la asignación en el montículo cuando los objetos necesiten sobrevivir a su ámbito o cuando su tamaño se determine en tiempo de ejecución.
Olvidar liberar la memoria del heap provoca fugas de memoria, una fuente común de errores en los programas de C++.
Desafío
FácilExploremos la diferencia entre la memoria stack y heap construyendo una clase Counter simple que rastrea cómo se crean y destruyen los objetos.
Crearás dos archivos para organizar tu código:
Counter.h: Define una claseCountercon un atributo privadoname(string). Incluye un constructor que reciba un nombre e imprima"Creating: <name>", y un destructor que imprima"Destroying: <name>". Añade un métodogetName()para devolver el nombre del contador.main.cpp: Demuestra la asignación tanto en stack como en heap. Lee un nombre de la entrada, luego:- Crea un
Counterasignado en el stack usando ese nombre - Crea un
Counterasignado en el heap con el nombre"HeapCounter" - Imprime ambos nombres de los contadores en el formato
"Stack: <name>"y"Heap: <name>" - Elimina el contador asignado en el heap para evitar una fuga de memoria
- Crea un
Observa cómo los mensajes del constructor y del destructor aparecen en diferentes órdenes según cuándo crees y elimines cada objeto. El objeto del stack se destruirá automáticamente cuando termine main(), mientras que el objeto del heap debe eliminarse explícitamente.
Incluye tu archivo de cabecera en main.cpp usando #include "Counter.h".
Hoja de referencia
Los programas en C++ utilizan dos regiones de memoria principales: la pila (stack) y el montículo (heap).
La pila es una memoria rápida y automática. Las variables declaradas dentro de las funciones viven aquí y se destruyen automáticamente cuando salen de su ámbito:
void example() {
int x = 10; // Stack allocation
Player player; // Stack allocation - destroyed automatically
} // x and player are destroyed hereEl montículo es una memoria más grande pero más lenta que se gestiona manualmente. Los objetos en el montículo persisten hasta que los eliminas explícitamente:
void example() {
Player* player = new Player(); // Heap allocation
// player exists until deleted
delete player; // Manual cleanup required
}Diferencias clave:
| Pila (Stack) | Montículo (Heap) |
|---|---|
| Asignación rápida | Asignación más lenta |
| Tamaño limitado | Gran capacidad |
| Limpieza automática | Requiere limpieza manual |
| Objetos de tamaño fijo | Objetos de tamaño dinámico |
Utiliza la asignación en la pila para objetos pequeños y de vida corta. Utiliza la asignación en el montículo cuando los objetos necesiten sobrevivir a su ámbito o cuando su tamaño se determine en tiempo de ejecución. Olvidar eliminar la memoria del montículo provoca fugas de memoria (memory leaks).
Pruébalo tú mismo
#include <iostream>
#include <string>
#include "Counter.h"
using namespace std;
int main() {
// Leer el nombre de la entrada
string inputName;
cin >> inputName;
// TODO: Crear un Counter asignado en la pila usando inputName
// TODO: Crear un Counter asignado en el montículo con el nombre "HeapCounter"
// TODO: Imprimir el nombre del contador de la pila en el formato "Stack: <name>"
// TODO: Imprimir el nombre del contador del montículo en el formato "Heap: <name>"
// TODO: Eliminar el contador asignado en el montículo para evitar fugas de memoria
return 0;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosConstrucción y compilación en C++Archivos de cabecera y archivos fuenteNamespaces y alcanceIntroducción a OOP en C++Clases vs ObjetosEl puntero 'this'Métodos (Funciones miembro)Atributos (Miembros de datos)Conceptos básicos de Ctors y DtorsResumen - Calculadora simple4Propiedades de clase
Miembros de instancia vs. estáticosGetters y SettersFunciones miembro constPalabra clave mutableMétodos y variables estáticosFunciones y clases amigasResumen - Gestor de cuentas bancarias7Herencia
Herencia básicaNiveles de acceso en la herenciaOrden de llamada de Ctor y DtorSobrescritura de métodosFunciones virtuales y VTableHerencia múltipleHerencia virtualResumen - Jerarquía de empleados2Gestión de memoria
Memoria Stack vs HeapPunteros y referenciasMemoria dinámica (new/delete)Punteros inteligentes en C++RAII en C++Resumen - Gestor de arrays dinámicos5Encapsulamiento
Especificadores de acceso en C++Especificadores de acceso en profundidadOcultamiento de informaciónStruct vs ClassClases anidadas e internasResumen - Sistema de registros de estudiantes8Polimorfismo
Polimorfismo: Compilación vs. Tiempo de ejecuciónSobrecarga de funcionesFunciones virtuales revisadasFunciones virtuales purasClases abstractasDiseño de interfaces en C++Dynamic Casting y RTTIResumen: Calculadora de figuras11Conceptos avanzados de POO
Composición vs. HerenciaMixins mediante CRTPIdioma PimplBorrado de tiposEnum Classes y tipado fuerteManejo de excepciones en POOJerarquías de excepciones personalizadas14Patrones de diseño - Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositeRAII como patrón3Constructores y Destructores
Constructor por defectoConstructor parametrizadoConstructor de copiaConstructor de movimientoListas de inicialización del constructorConstructores delegadosAnálisis profundo del destructorRegla de tres / cinco / ceroResumen - Clase String6Sobrecarga de operadores
Introducción a la sobrecarga de operadoresSobrecarga de operadores aritméticosSobrecarga de operadores de comparaciónOperadores de flujo (Stream)Sobrecarga del operador de asignaciónSobrecarga de los operadores [] y ()Operadores de conversión de tiposResumen - Clase Matrix9Plantillas
Plantillas de funcionesPlantillas de clasesEspecialización de plantillasPlantillas variádicasConceptos básicos de SFINAE y Type TraitsResumen - Contenedor genérico