Memoria dinámica (new/delete)
Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy. Lección 14 de 104.
Ahora que entiendes los punteros y las referencias, vamos a ponerlos en práctica con la asignación dinámica de memoria. Los operadores new y delete te permiten crear y destruir objetos en el montón durante la ejecución.
Usa new para asignar memoria y obtener un puntero a ella:
int* num = new int; // Reserva memoria para un solo entero
*num = 42; // Asigna un valor mediante el puntero
Player* player = new Player("Hero"); // Reserva memoria para un objetoCada new debe tener un delete correspondiente para liberar la memoria:
delete num; // Libera un único objeto
delete player; // Llama al destructor y luego libera la memoriaPara los arreglos, usa new[] y delete[]:
int* scores = new int[5]; // Reserva memoria para un arreglo de 5 enteros
scores[0] = 100;
delete[] scores; // Libera la memoria del arreglo: ¡fíjate en los corchetes!Errores comunes que debes evitar:
// Fuga de memoria: se olvidó usar delete
int* ptr = new int(10);
ptr = new int(20); // ¡Se perdió el acceso a la primera asignación de memoria!
// Puntero colgante: se usa después de delete
delete ptr;
*ptr = 5; // ¡Comportamiento indefinido!
// Uso incorrecto de delete
int* arr = new int[10];
delete arr; // ¡Incorrecto! Debería ser delete[]Después de eliminar, asigna nullptr a los punteros para evitar reutilizarlos accidentalmente. La gestión manual de la memoria es propensa a errores, por eso el C++ moderno prefiere los punteros inteligentes, que exploraremos a continuación.
Desafío
FácilVamos a crear un sistema sencillo de almacenamiento de mensajes que demuestre la asignación dinámica de memoria con new y delete.
Crearás dos archivos para organizar tu código:
MessageBox.h: Define una claseMessageBoxque gestione dinámicamente un arreglo de mensajes. La clase debe tener:- Un puntero privado a un arreglo de cadenas asignado dinámicamente
- Un entero privado que registre la cantidad actual de mensajes
- Un entero privado que almacene la capacidad máxima
- Un constructor que reciba una capacidad y asigne el arreglo usando
new[] - Un destructor que libere correctamente la memoria usando
delete[]e imprima"MessageBox destroyed" - Un método
addMessage(string msg)que agregue un mensaje si hay espacio y devuelvatruesi tiene éxito ofalsesi está lleno - Un método
printAll()que imprima cada mensaje almacenado en su propia línea
main.cpp: Lee un valor de capacidad y una cantidad de mensajes desde la entrada. Después, lee esa cantidad de cadenas de mensajes. Crea unMessageBoxen el montículo usandonew, agrega todos los mensajes, llama aprintAll()y luego elimina correctamente el MessageBox para liberar la memoria.
El formato de entrada será:
- Primera línea: la capacidad (entero)
- Segunda línea: la cantidad de mensajes que se agregarán (entero)
- Líneas siguientes: un mensaje por línea
Recuerda: cada new necesita un delete correspondiente, y cada new[] necesita un delete[] correspondiente. Después de eliminar, es recomendable establecer los punteros en nullptr.
Incluye el archivo de encabezado en main.cpp usando #include "MessageBox.h".
Pruébalo tú mismo
#include <iostream>
#include <string>
#include "MessageBox.h"
using namespace std;
int main() {
int capacity;
int numMessages;
// Lee la capacidad y el número de mensajes
cin >> capacity;
cin >> numMessages;
cin.ignore(); // Elimina el salto de línea después del número
// TODO: Crea un MessageBox en el montón usando new
// TODO: Lee y añade todos los mensajes al MessageBox
for (int i = 0; i < numMessages; i++) {
string message;
getline(cin, message);
// Añade el mensaje al MessageBox
}
// TODO: Llama a printAll() para mostrar todos los mensajes
// TODO: Elimina el MessageBox para liberar memoria
// Recuerda establecer el puntero en nullptr después de eliminarlo
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 la POO
Archivos externosCompilación y construcción en C++Archivos de cabecera y archivos fuenteEspacios de nombres y ámbitoIntroducción a la POO en C++Clases y objetosEl puntero 'this'Métodos (funciones miembro)Atributos (miembros de datos)Fundamentos de constructores y destructoresRepaso: calculadora sencilla4Propiedades de clase
Miembros de instancia vs. estáticosGetters y settersFunciones miembro constPalabra clave mutableMétodos y variables estáticosFunciones y clases friendRepaso: gestor de cuentas bancarias7Herencia
Herencia básicaNiveles de acceso en la herenciaOrden de llamada de constructores y destructoresSobrescritura de métodosFunciones virtuales y VTableHerencia múltipleHerencia virtualRepaso: jerarquía de empleados2Gestión de memoria
Memoria de pila vs. heapPunteros y referenciasMemoria dinámica (new/delete)Punteros inteligentes en C++RAII en C++Repaso: gestor de arreglos dinámicos5Encapsulación
Especificadores de acceso en C++Especificadores de acceso en profundidadOcultación de informaciónStruct vs. classClases anidadas e internasRepaso: sistema de registros de estudiantes8Polimorfismo
Polimorfismo en compilación y en tiempo de ejecuciónSobrecarga de funcionesRepaso de las funciones virtualesFunciones virtuales purasClases abstractasDiseño de interfaces en C++Conversión dinámica y RTTIRepaso: calculadora de formas11Conceptos avanzados de POO
Composición frente a herenciaMixins mediante CRTPIdiom PimplBorrado de tiposClases enum 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 predeterminadoConstructor con parámetrosConstructor de copiaConstructor de movimientoListas de inicialización del constructorConstructores delegadosAnálisis detallado del destructorRegla de tres / cinco / ceroRepaso: clase String6Sobrecarga de operadores
Introducción a la sobrecarga de operadoresSobrecarga de operadores aritméticosSobrecarga de operadores de comparaciónOperadores de flujoSobrecarga del operador de asignaciónSobrecarga de los operadores [] y ()Operadores de conversión de tipoRepaso: clase Matrix9Plantillas
Plantillas de funcionesPlantillas de clasesEspecialización de plantillasPlantillas variádicasFundamentos de SFINAE y rasgos de tiposRepaso: contenedor genéricoPractica por tu cuenta: Compilador de C++ online