Patrón Destructor
Parte de la sección Programación Orientada a Objetos del Journey de C de Coddy. Lección 13 de 61.
Todo objeto creado con malloc debe liberarse en algún momento. Así como escribimos una función create_ para gestionar la asignación, escribimos una función free_ para gestionar la limpieza. Este es el patrón destructor.
La idea clave es que la liberación debe realizarse en el orden inverso al de la asignación. Si tu constructor asignó primero los miembros internos y después la propia estructura, tu destructor debe liberar primero los miembros de la estructura y después la estructura:
typedef struct {
char *name;
int age;
} Person;
void free_person(Person *p) {
if (p == NULL) return; // Comprobación de seguridad
free(p->name); // Liberar el miembro interno primero
free(p); // Luego liberar la estructura en sí
}
La comprobación de NULL al principio evita errores si alguien pasa accidentalmente un puntero no válido. Después de liberar la cadena interna name, liberamos la propia estructura. Si liberáramos p primero, perderíamos el acceso a p->name y provocaríamos una fuga de memoria.
Usar el destructor es sencillo:
Person *alice = create_person("Alice", 30);
// ... usa alice ...
free_person(alice); // Limpia cuando hayas terminado
Este patrón garantiza que toda la memoria se libere correctamente. Sin él, cada objeto que crees tendría una fuga de memoria hasta que tu programa se quedara sin memoria.
Desafío
FácilConstruyamos un módulo Movie que demuestre el ciclo de vida completo de un objeto: tanto su creación como su destrucción. Practicarás cómo escribir una función destructora que libere correctamente toda la memoria asignada y en el orden adecuado.
Crearás tres archivos:
movie.h: Declara una estructuraMoviecon dos miembros:char *title(una cadena asignada dinámicamente) yint year. Declara tanto un constructorcreate_movieque recibe un título y un año, como un destructorfree_movieque recibe un puntero a Movie. Usa protectores de inclusión con el símboloMOVIE_H.movie.c: Implementa ambas funciones. Tu constructor debe asignar memoria para la estructura y para su cadena de título (no olvides el terminador nulo). Tu destructor debe liberar la memoria en el orden inverso al de la asignación: primero la cadena internatitley después la propia estructura. Incluye una comprobación de NULL al principio del destructor por seguridad.main.c: Crea una película, muestra su información y después libera correctamente la memoria.
Recibirás dos entradas: el título de la película (una cadena) y el año de estreno (un entero).
En tu archivo principal, usa create_movie para crear una película nueva, imprime su información y después llama a free_movie para liberar toda la memoria. Después de liberarla, imprime un mensaje de confirmación.
Imprime la salida con este formato:
Movie: {title} ({year})
Memory freedPor ejemplo, con las entradas Inception y 2010, la salida sería:
Movie: Inception (2010)
Memory freedRecuerda: la clave para un destructor correcto es liberar en el orden inverso. Lo que tu constructor asigne primero se libera al final, y lo que asigne al final se libera primero.
Pruébalo tú mismo
#include <stdio.h>
#include <stdlib.h>
#include "movie.h"
int main() {
char title[100];
int year;
// Leer entrada
scanf("%[^\n]", title);
scanf("%d", &year);
// TODO: Crea una película usando create_movie
// TODO: Imprime la información de la película en el formato:
// Movie: {title} ({year})
// TODO: Libera la película usando free_movie
// TODO: Imprime "Memory freed"
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 programación modular
Archivos de cabeceraGuardas de inclusiónArchivos fuenteFunciones estáticasRepaso: Calculadora modular4Encapsulamiento
Concepto de punteros opacosDefinición de structs opacosGetters y SettersValidación en settersResumen: Caja secreta7Punteros a funciones
Declaración de punteros a funcionesLlamada a punteros a funcionesTypedef para punteros a funcionesPasar funciones como argumentosRepaso: Dispatch de calculadora10Contenedores genéricos
Repaso de punteros voidWrapper genéricoSwap genéricoComparación genéricaRepaso: Array genérico2Objetos y métodos
Structs como objetosEl puntero 'Self'Const CorrectnessPuntero vs. ValorMétodos auxiliaresResumen: Point Manager5Proyecto: Cuenta bancaria simple
Configuración del proyectoImplementación de la cuenta3Ciclo de vida de los objetos
Patrón ConstructorPatrón DestructorInicialización en StackCopia profundaResumen: String Wrapper6Herencia mediante composición
Incrustación de StructsLa regla del primer miembroAcceso a miembros padreUpcastingResumen: Jerarquía de formas9Proyecto: Dibujador de figuras
Descripción general del proyectoImplementación del círculoImplementación del rectánguloUso polimórficoContenedor de figurasPractica por tu cuenta: Compilador de C online