Padrão de destrutor
Parte da seção Programação Orientada a Objetos do Journey de C da Coddy. Lição 13 de 61.
Todo objeto criado com malloc precisa ser liberado eventualmente. Assim como escrevemos uma função create_ para cuidar da alocação, escrevemos uma função free_ para cuidar da limpeza. Esse é o padrão de destrutor.
A principal ideia é que a liberação deve acontecer na ordem inversa à da alocação. Se o seu construtor alocou primeiro os membros internos e depois a própria struct, o destrutor deve liberar primeiro os membros da struct 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); // Libere primeiro o membro interno
free(p); // Depois libere a própria struct
}
A verificação de NULL no início evita falhas caso alguém passe acidentalmente um ponteiro inválido. Depois de liberar a string interna name, 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); // Libere os recursos ao terminar
Esse padrão garante que toda a memória seja liberada corretamente. Sem ele, cada objeto que você criar causaria vazamento de memória até que o programa ficasse sem memória.
Desafio
FácilVamos criar um módulo Movie que demonstra o ciclo de vida completo de um objeto: tanto a criação quanto a destruição. Você vai praticar a escrita de uma função destrutora que libera corretamente toda a memória alocada, na ordem certa.
Você criará três arquivos:
movie.h: Declare uma estruturaMoviecom dois membros:char *title(uma string alocada dinamicamente) eint year. Declare tanto um construtorcreate_movie, que recebe um título e um ano, quanto um destrutorfree_movie, que recebe um ponteiro para Movie. Use proteções de inclusão com o símboloMOVIE_H.movie.c: Implemente as duas funções. Seu construtor deve alocar memória para a estrutura e sua string de título (não se esqueça do terminador nulo). Seu destrutor deve liberar a memória na ordem inversa à da alocação: primeiro a string internatitlee, depois, a própria estrutura. Inclua uma verificação de NULL no início do destrutor, por segurança.main.c: Crie um filme, exiba suas informações e, em seguida, libere a memória corretamente.
Você receberá duas entradas: o título do filme (uma string) e o ano de lançamento (um inteiro).
Em seu arquivo principal, use create_movie para criar um novo filme, imprimir suas informações e, em seguida, chame free_movie para liberar toda a memória. Depois de liberar a memória, 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: o segredo para um destrutor correto é liberar a memória na ordem inversa. O que o construtor aloca primeiro é liberado por último, e o que ele aloca por último é liberado primeiro.
Experimente você mesmo
#include <stdio.h>
#include <stdlib.h>
#include "movie.h"
int main() {
char title[100];
int year;
// Leia a entrada
scanf("%[^\n]", title);
scanf("%d", &year);
// TODO: Crie um filme usando create_movie
// TODO: Imprima as informações do filme no formato:
// Filme: {title} ({year})
// TODO: Libere a memória do filme usando free_movie
// TODO: Imprima "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 Programação Orientada a Objetos
1Fundamentos da Programação Modular
Arquivos de cabeçalhoProteções de inclusãoArquivos-fonteFunções estáticasRevisão: calculadora modular4Encapsulamento
Conceito de ponteiros opacosDefinindo structs opacasGetters e settersValidação em settersRevisão: caixa secreta2Objetos e métodos
Structs como objetosO ponteiro 'Self'Correção de constPonteiro vs. valorMétodos auxiliaresRevisão: Gerenciador de pontos5Projeto: Conta Bancária Simples
Configuração do ProjetoImplementação da Conta3Ciclo de vida do objeto
Padrão de construtorPadrão de destrutorInicialização da pilhaCópia profundaRevisão: wrapper de String6Herança por composição
Incorporação de structRegra do primeiro membroAcessando membros do tipo paiUpcastingRevisão: hierarquia de formas9Projeto: Desenhador de Formas
Visão geral do projetoImplementação do círculoImplementação do retânguloUso polimórficoContêiner de formasPratique por conta própria: Compilador de C online