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 ciclo 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 recebe 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";
}
};Destructors 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. Não é possível 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.
Desafio
FácilVamos criar um gerenciador de sessões que rastreia 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 excluídos explicitamente.
Você criará dois arquivos para organizar seu código:
Session.h: defina uma classeSessionque represente uma sessão de usuário ativa com dados alocados dinamicamente. Sua classe deve ter:- Membros privados: um
username(string), umsessionId(int) e um ponteiro para um array de inteiros chamadoactivityLogque rastreia as ações do usuário, além de umlogSizepara o tamanho do array - Um construtor que receba um username, um ID de sessão e o tamanho do 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 destruidor 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 (rastreie internamente a posição atual) - Um método
getActivityCount()que retorne quantas atividades foram registradas - Um método
getUsername()que retorne o username
- Membros privados: um
main.cpp: demonstre o comportamento do destruidor em diferentes cenários. Leia um username 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 umaSessionalocada na stack com o username informado, o ID de sessão101e o tamanho de log informado. Registre duas atividades com os códigos1e2e, em seguida, imprima"Stack session activities: <count>". Quando o bloco terminar, o destruidor deverá ser executado automaticamente. - Após o bloco, imprima
"Stack session destroyed" - Crie uma
Sessionalocada no heap usandonew, com o username"Guest", o ID de sessão202e o tamanho de log3. Registre uma atividade com o código5, imprima"Heap session activities: <count>"e, em seguida, use explicitamentedeletenela. - Após a exclusão, imprima
"Heap session destroyed"
- Crie um bloco de escopo usando chaves
Este desafio mostra as duas principais maneiras pelas quais os destruidores são chamados: automaticamente, quando os objetos na stack 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;
}
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 de POO
Arquivos externosBuild e compilação em C++Arquivos de cabeçalho e arquivos-fonteNamespaces e escopoIntrodução à POO em C++Classes vs. objetosO ponteiro 'this'Métodos (funções membro)Atributos (membros de dados)Noções básicas de construtores e destruidoresRevisão - calculadora simples4Propriedades de Classe
Membros de Instância vs. EstáticosGetters e SettersFunções Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRevisão - Gerenciador de Contas Bancárias7Herança
Herança básicaNíveis de acesso da herançaOrdem de chamada de construtor e destrutorSobrescrita de métodosFunções virtuais e VTableHerança múltiplaHerança virtualRevisão - Hierarquia de funcionários10Visão geral da STL
Visão geral e filosofia da STLContêineres da STLIteradoresAlgoritmos da STLFunctors e expressões lambdaRecapitulação - Frequência de palavras13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonFactory e Abstract FactoryPadrão BuilderPadrão ObserverPadrão Strategy2Gerenciamento de Memória
Memória Stack vs. HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Ponteiros Inteligentes em C++RAII em C++Revisão - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de acesso em C++Especificadores de acesso em profundidadeOcultação de informaçõesStruct vs ClasseClasses aninhadas e internasRecapitulação - Sistema de registros de alunos8Polimorfismo
Polimorfismo em compilação vs. execuçãoSobrecarga de funçõesFunções virtuais revisadasFunções virtuais purasClasses abstratasDesign de interfaces em C++Conversão dinâmica e RTTIRecapitulação — Calculadora de formas11Conceitos Avançados de OOP
Composição vs. HerançaMixins via CRTPIdioma PimplApagamento de TiposClasses Enum e Tipagem ForteTratamento de Exceções em OOPHierarquias de Exceções Personalizadas14Padrões de Projeto — Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositeRAII como Padrão3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentoListas de Inicialização do ConstrutorConstrutores DelegantesAprofundamento em DestrutoresRegra dos Três / Cinco / ZeroRevisão - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de FluxoSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçõesTemplates de ClassesEspecialização de TemplatesTemplates VariádicosNoções Básicas de SFINAE e Traits de TiposRecapitulação - Contêiner GenéricoPratique por conta própria: Compilador de C++ online