RAII em C++
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy. Lição 16 de 104.
RAII (Resource Acquisition Is Initialization) é um idioma fundamental do C++, no qual o gerenciamento de recursos está vinculado ao tempo de vida do objeto. A ideia é simples: adquirir recursos no construtor e liberá-los no destrutor.
Quando um objeto é criado, ele adquire todos os recursos de que precisa. Quando o objeto sai do escopo, seu destrutor libera automaticamente esses recursos. Isso garante a limpeza mesmo que ocorram exceções.
class FileHandler {
std::FILE* file;
public:
FileHandler(const char* filename) {
file = std::fopen(filename, "r"); // Adquirir recurso
}
~FileHandler() {
if (file) std::fclose(file); // Liberar recurso
}
};Com RAII, você nunca se esquece de fazer a limpeza:
void processFile() {
FileHandler handler("data.txt"); // Recurso adquirido
// Trabalhe com o arquivo...
// Se uma exceção for lançada aqui, o destrutor ainda é executado!
} // Recurso liberado automaticamenteOs ponteiros inteligentes são o exemplo perfeito de RAII em ação. Um unique_ptr adquire a propriedade da memória do heap em seu construtor e a exclui em seu destrutor. Você já estava usando RAII sem perceber!
RAII se aplica a qualquer recurso: memória, identificadores de arquivo, conexões de rede, mutexes ou conexões de banco de dados. Ao encapsular recursos em objetos, o C++ garante uma limpeza determinística e elimina categorias inteiras de bugs, como vazamentos e identificadores pendentes.
Desafio
FácilVamos criar um gerenciador de conexões que demonstra RAII ao lidar automaticamente com o ciclo de vida de conexões semelhantes a conexões de rede. Quando uma conexão é criada, ela deve ser "aberta" e, quando sai do escopo, deve ser automaticamente "fechada": nenhuma limpeza manual é necessária!
Você criará dois arquivos para organizar seu código:
Connection.h: Defina uma classeConnectionque gerencie um recurso de conexão usando os princípios de RAII. A classe deve ter:- Um atributo privado
connectionId(string) para identificar a conexão - Um atributo privado
isOpen(bool) para acompanhar o estado da conexão - Um construtor que receba um ID de conexão, defina
isOpencomo true e imprima"Opening connection: <id>" - Um destrutor que verifique se a conexão está aberta, feche-a definindo
isOpencomo false e imprima"Closing connection: <id>" - Um método
send(string message)que imprima"[<id>] Sending: <message>"se a conexão estiver aberta - Um método
getId()que retorne o ID da conexão
- Um atributo privado
main.cpp: Demonstre como o RAII garante a limpeza automática lendo um ID de conexão e uma mensagem da entrada. Em seguida:- Crie um escopo usando chaves
{ } - Dentro desse escopo, crie um objeto
Connectionna pilha com o ID informado - Use a conexão para enviar a mensagem informada
- Deixe o escopo terminar (a conexão deve ser fechada automaticamente)
- Após o escopo, imprima
"Connection out of scope"
- Crie um escopo usando chaves
A beleza do RAII é que você não precisa se lembrar de fechar a conexão: o destrutor cuida disso automaticamente quando o objeto sai do escopo. Esse padrão evita vazamentos de recursos mesmo que algo inesperado aconteça no seu código.
Inclua seu arquivo de cabeçalho em main.cpp usando #include "Connection.h".
Experimente você mesmo
#include <iostream>
#include <string>
#include "Connection.h"
using namespace std;
int main() {
string connectionId;
string message;
// Ler entrada
cin >> connectionId;
cin.ignore();
getline(cin, message);
// TODO: Crie um escopo usando chaves { }
// Dentro do escopo:
// - Crie um objeto Connection na pilha com connectionId
// - Use a conexão para enviar a mensagem
// Deixe o escopo terminar (o destrutor será chamado automaticamente)
// TODO: After the scope ends, print "Connection out of scope"
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