Menu
Coddy logo textTech

Mergulho Profundo em Destrutores

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 24 de 104.

Um destrutor é uma função membro especial que é executada automaticamente quando um objeto é destruído. Seu trabalho principal é liberar recursos que o objeto adquiriu durante seu tempo de vida, como memória alocada dinamicamente, manipuladores de arquivos ou conexões de rede.

O destrutor tem o mesmo nome que a classe, prefixado com um til ~. Ele não recebe parâmetros e não possui tipo de retorno:

class FileHandler {
    std::string filename;
    int* buffer;
public:
    FileHandler(std::string name, size_t size) 
        : filename(name), buffer(new int[size]) {
        std::cout << "Opening " << filename << "\n";
    }
    
    ~FileHandler() {
        delete[] buffer;
        std::cout << "Closing " << filename << "\n";
    }
};

Destrutores são chamados automaticamente nestas situações:

  • Objetos de pilha saem de escopo
  • delete é chamado em um objeto alocado no heap
  • O tempo de vida de um objeto temporário termina
void example() {
    FileHandler f1("data.txt", 100);    // Construtor chamado
    
    FileHandler* f2 = new FileHandler("log.txt", 50);
    delete f2;                           // Destrutor chamado para f2
    
}   // Destrutor chamado para f1 (sai do escopo)

Ao contrário dos construtores, uma classe pode ter apenas um destrutor. Você não pode sobrecarregá-lo.

Se você não definir um, o compilador gera um destrutor padrão que não faz nada de especial - ele simplesmente destrói cada membro. Para classes que gerenciam recursos, você deve escrever o seu próprio para evitar vazamentos de memória.

challenge icon

Desafio

Fácil

Vamos construir um gerenciador de sessões que rastreia sessões de usuários ativos e demonstra como os destrutores limpam automaticamente os recursos quando os objetos são destruídos — seja quando saem de escopo ou quando são explicitamente deletados.

Você criará dois arquivos para organizar seu código:

  • Session.h: Defina uma classe Session que representa uma sessão de usuário ativa com dados alocados dinamicamente. Sua classe deve ter:
    • Membros privados: um username (string), um sessionId (int) e um ponteiro para um array de inteiros chamado activityLog que rastreia as ações do usuário, junto com um logSize para o tamanho do array
    • Um construtor que recebe um nome de usuário, ID da sessão e tamanho do log. Ele deve alocar o array do log de atividades no heap, inicializar todos os elementos com 0 e imprimir "Session <sessionId> started for <username>"
    • Um destrutor que libera a memória alocada e imprime "Session <sessionId> ended for <username>"
    • Um método logActivity(int activityCode) que armazena o código da atividade no próximo slot disponível (rastreie a posição atual internamente)
    • Um método getActivityCount() que retorna quantas atividades foram registradas
    • Um método getUsername() que retorna o nome de usuário
  • main.cpp: Demonstre o comportamento do destrutor em diferentes cenários. Leia um nome de usuário e o tamanho do log da entrada (cada um em uma linha separada) e, em seguida:
    • Crie um bloco de escopo usando chaves { } e, dentro dele, crie uma Session alocada na pilha (stack) com o nome de usuário de entrada, ID de sessão 101 e o tamanho do log de entrada. Registre duas atividades com os códigos 1 e 2, depois imprima "Stack session activities: <count>". Quando o bloco terminar, o destrutor deve ser executado automaticamente.
    • Após o bloco, imprima "Stack session destroyed"
    • Crie uma Session alocada no heap usando new com o nome de usuário "Guest", ID de sessão 202 e tamanho de log 3. Registre uma atividade com o código 5, imprima "Heap session activities: <count>" e, em seguida, use explicitamente delete nela.
    • Após a exclusão, imprima "Heap session destroyed"

Este desafio mostra as duas principais maneiras pelas quais os destrutores são chamados: automaticamente quando objetos da pilha saem de escopo e manualmente quando você deleta objetos do heap. Ambos os caminhos devem liberar adequadamente o log de atividades alocado dinamicamente para evitar vazamentos de memória.

Inclua seu arquivo de cabeçalho no main.cpp usando #include "Session.h".

Folha de consulta

Um destrutor é uma função membro especial que é executada automaticamente quando um objeto é destruído. Ele libera recursos como memória alocada dinamicamente, manipuladores de arquivos ou conexões de rede.

O destrutor tem o mesmo nome da classe, prefixado com um til ~. Ele não recebe parâmetros e não possui tipo de retorno:

class FileHandler {
    std::string filename;
    int* buffer;
public:
    FileHandler(std::string name, size_t size) 
        : filename(name), buffer(new int[size]) {
        std::cout << "Opening " << filename << "\n";
    }
    
    ~FileHandler() {
        delete[] buffer;
        std::cout << "Closing " << filename << "\n";
    }
};

Os destrutores são chamados automaticamente quando:

  • Objetos de pilha saem de escopo
  • delete é chamado em um objeto alocado no heap
  • O tempo de vida de um objeto temporário termina
void example() {
    FileHandler f1("data.txt", 100);    // Construtor chamado
    
    FileHandler* f2 = new FileHandler("log.txt", 50);
    delete f2;                           // Destrutor chamado para f2
    
}   // Destrutor chamado para f1 (sai de escopo)

Uma classe pode ter apenas um destrutor (sem sobrecarga). Se você não definir um, o compilador gera um destrutor padrão. Para classes que gerenciam recursos, você deve escrever o seu próprio para evitar vazamentos de memória.

Experimente você mesmo

#include <iostream>
#include <string>
#include "Session.h"

using namespace std;

int main() {
    // Ler entrada
    string username;
    int logSize;
    getline(cin, username);
    cin >> logSize;
    
    // TODO: Criar um bloco de escopo com chaves { }
    // Dentro do bloco:
    //   - Criar uma Session alocada na stack com o username de entrada, ID de sessão 101 e o tamanho de log de entrada
    //   - Registrar duas atividades com os códigos 1 e 2
    //   - Imprimir "Stack session activities: <count>"
    // Quando o bloco termina, o destrutor é executado automaticamente
    
    // TODO: Após o bloco, imprimir "Stack session destroyed"
    
    // TODO: Criar uma Session alocada na heap usando new
    //   - Username: "Guest", ID de sessão: 202, tamanho de log: 3
    //   - Registrar uma atividade com o código 5
    //   - Imprimir "Heap session activities: <count>"
    //   - Deletar a sessão
    
    // TODO: Após a exclusão, imprimir "Heap session destroyed"
    
    return 0;
}
quiz iconTeste seus conhecimentos

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