Menu
CoddyTech

Aprofundamento 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. Sua principal função é liberar os recursos que o objeto adquiriu durante seu tempo de vida, como memória alocada dinamicamente, identificadores de arquivo ou conexões de rede.

O destrutor tem o mesmo nome da classe, precedido por um til ~. Ele não aceita parâmetros e não tem 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 nestas situações:

  • Objetos na pilha saem do escopo
  • delete é chamado em um objeto alocado na 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 criar um gerenciador de sessões que acompanha as sessões de usuários ativas e demonstra como os destruidores limpam automaticamente os recursos quando os objetos são destruídos, seja quando saem do escopo ou quando são explicitamente excluídos.

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

  • Session.h: defina uma classe Session que represente 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 acompanha as ações do usuário, juntamente com um logSize para o tamanho do array
    • Um construtor que receba um nome de usuário, um ID de sessão e um tamanho de log. Ele deve alocar o array de log de atividades no heap, inicializar todos os elementos com 0 e imprimir "Session <sessionId> started for <username>"
    • Um destrutor que libere a memória alocada e imprima "Session <sessionId> ended for <username>"
    • Um método logActivity(int activityCode) que armazene o código da atividade no próximo espaço disponível (acompanhe a posição atual internamente); se o log já estiver cheio, a chamada será ignorada, para que a quantidade nunca exceda o tamanho do log
    • Um método getActivityCount() que retorne quantas atividades foram registradas
    • Um método getUsername() que retorne o nome de usuário
  • main.cpp: demonstre o comportamento dos destruidores 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 com o nome de usuário fornecido, o ID de sessão 101 e o tamanho de log fornecido. Registre duas atividades com os códigos 1 e 2 e, em seguida, imprima "Stack session activities: <count>". Quando o bloco terminar, o destrutor deverá ser executado automaticamente.
    • Depois do bloco, imprima "Stack session destroyed"
    • Crie uma Session alocada no heap usando new, com o nome de usuário "Guest", o ID de sessão 202 e o tamanho de log 3. Registre uma atividade com o código 5, imprima "Heap session activities: <count>" e, em seguida, use explicitamente delete nela.
    • Depois da exclusão, imprima "Heap session destroyed"

Este desafio mostra as duas principais formas de os destruidores serem chamados: automaticamente, quando os objetos na pilha saem do escopo, e manualmente, quando você exclui objetos no heap. Ambos os caminhos devem liberar corretamente o log de atividades alocado dinamicamente para evitar vazamentos de memória.

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

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: Crie um bloco de escopo com chaves { }
    // Dentro do bloco:
    //   - Crie um Session alocado na stack com o username de entrada, session ID 101 e o log size de entrada
    //   - Registre duas atividades com códigos 1 e 2
    //   - Print "Stack session activities: <count>"
    // Quando o bloco termina, o destrutor é executado automaticamente
    
    // TODO: After the block, print "Stack session destroyed"
    
    // TODO: Crie um Session alocado na heap usando new
    //   - Username: "Guest", session ID: 202, log size: 3
    //   - Registre uma atividade com código 5
    //   - Print "Heap session activities: <count>"
    //   - Delete a sessão
    
    // TODO: After deletion, print "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

Pratique por conta própria: Compilador de C++ online