Padrão de Destrutor
Parte da seção Object Oriented Programming do Journey de C da Coddy — lição 13 de 61.
Todo objeto criado com malloc deve eventualmente ser liberado. Assim como escrevemos uma função create_ para lidar com a alocação, escrevemos uma função free_ para lidar com a limpeza. Este é o padrão destrutor.
A percepção fundamental é que a liberação deve ocorrer na ordem inversa da alocação. Se o seu construtor alocou membros internos primeiro e depois a própria struct, seu destrutor deve liberar os membros da struct primeiro e, em seguida, a struct:
typedef struct {
char *name;
int age;
} Person;
void free_person(Person *p) {
if (p == NULL) return; // Verificação de segurança
free(p->name); // Libera o membro interno primeiro
free(p); // Depois libera a própria struct
}
A verificação de NULL no início evita falhas se alguém acidentalmente passar um ponteiro inválido. Após liberar a string name interna, liberamos a própria struct. Se liberássemos p primeiro, perderíamos o acesso a p->name e causaríamos um vazamento de memória.
Usar o destrutor é simples:
Person *alice = create_person("Alice", 30);
// ... use alice ...
free_person(alice); // Limpe ao terminar
Este padrão garante que toda a memória seja liberada adequadamente. Sem ele, cada objeto que você criar causaria vazamento de memória até que seu programa ficasse sem ela.
Desafio
FácilVamos construir um módulo Movie que demonstra o ciclo de vida completo de um objeto — tanto a criação quanto a destruição. Você praticará a escrita de uma função destruidora que limpa adequadamente toda a memória alocada na ordem correta.
Você criará três arquivos:
movie.h: Declare uma structMoviecom dois membros:char *title(uma string alocada dinamicamente) eint year. Declare tanto um construtorcreate_movieque recebe um título e um ano, quanto um destruidorfree_movieque recebe um ponteiro para Movie. Use include guards com o símboloMOVIE_H.movie.c: Implemente ambas as funções. Seu construtor deve alocar memória para a struct e para sua string de título (não se esqueça do terminador nulo). Seu destruidor deve liberar a memória na ordem inversa da alocação — primeiro a string internatitle, depois a própria struct. Inclua uma verificação de NULL no início do seu destruidor por segurança.main.c: Crie um filme, exiba suas informações e, em seguida, limpe adequadamente a memória.
Você receberá duas entradas: o título do filme (uma string) e o ano de lançamento (um inteiro).
No seu arquivo principal, use create_movie para criar um novo filme, imprima suas informações e, em seguida, chame free_movie para liberar toda a memória. Após a liberação, imprima uma mensagem de confirmação.
Imprima a saída neste formato:
Movie: {title} ({year})
Memory freedPor exemplo, com as entradas Inception e 2010, a saída seria:
Movie: Inception (2010)
Memory freedLembre-se: a chave para um destruidor adequado é liberar na ordem inversa. O que seu construtor aloca primeiro é liberado por último, e o que ele aloca por último é liberado primeiro.
Folha de consulta
Todo objeto criado com malloc deve ser liberado usando uma função destrutora. Destrutores seguem o padrão de liberar memória na ordem inversa da alocação.
Estrutura básica de um destrutor:
typedef struct {
char *name;
int age;
} Person;
void free_person(Person *p) {
if (p == NULL) return; // Verificação de segurança
free(p->name); // Libera os membros internos primeiro
free(p); // Depois libera a própria struct
}
Princípios fundamentais:
- Sempre inclua uma verificação de
NULLno início para evitar falhas - Libere os membros internos antes de liberar a própria struct
- Se você liberar a struct primeiro, perderá o acesso aos seus membros e causará vazamentos de memória
Exemplo de uso:
Person *alice = create_person("Alice", 30);
// ... use alice ...
free_person(alice); // Limpa ao terminar
Experimente você mesmo
#include <stdio.h>
#include <stdlib.h>
#include "movie.h"
int main() {
char title[100];
int year;
// Ler entrada
scanf("%[^\n]", title);
scanf("%d", &year);
// TODO: Criar um filme usando create_movie
// TODO: Imprimir as informações do filme no formato:
// Movie: {title} ({year})
// TODO: Liberar o filme usando free_movie
// TODO: Imprimir "Memory freed"
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Fundamentos da Programação Modular
Arquivos de CabeçalhoInclude GuardsArquivos-FonteFunções EstáticasRecapitulação: Calculadora Modular4Encapsulamento
Conceito de Ponteiros OpacosDefinindo Structs OpacasGetters e SettersValidação em SettersRecapitulação: Caixa Secreta2Objetos e Métodos
Structs como ObjetosO Ponteiro 'Self'Const CorrectnessPonteiro vs ValorMétodos AuxiliaresRecapitulação: Point Manager5Projeto: Conta Bancária Simples
Configuração do ProjetoImplementação da Conta3Ciclo de Vida de Objetos
Padrão de ConstrutorPadrão de DestrutorInicialização na StackCópia ProfundaRecapitulação: String Wrapper6Herança via Composição
Incorporação de StructsA Regra do Primeiro MembroAcessando Membros PaiUpcastingRecapitulação: Hierarquia de Formas9Projeto: Desenhador de Formas
Visão Geral do ProjetoImplementação do Círculo