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 - Aquisição de Recurso é Inicialização) é um idioma fundamental de C++ onde o gerenciamento de recursos está vinculado ao tempo de vida do objeto. A ideia é simples: adquirir recursos no construtor, liberá-los no destrutor.
Quando um objeto é criado, ele adquire quaisquer recursos de que necessita. Quando o objeto sai de 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"); // Adquire o recurso
}
~FileHandler() {
if (file) std::fclose(file); // Libera o recurso
}
};Com RAII, você nunca esquece de realizar a limpeza:
void processFile() {
FileHandler handler("data.txt"); // Recurso adquirido
// Trabalha com o arquivo...
// Se uma exceção for lançada aqui, o destrutor ainda será executado!
} // Recurso liberado automaticamenteSmart pointers são o exemplo perfeito de RAII em ação. Um unique_ptr adquire a propriedade da memória heap em seu construtor e a deleta em seu destrutor. Você já vem usando RAII sem perceber!
RAII se aplica a qualquer recurso: memória, manipuladores de arquivos, conexões de rede, mutexes ou conexões de banco de dados. Ao envolver recursos em objetos, o C++ garante a limpeza determinística e elimina categorias inteiras de bugs, como vazamentos e manipuladores pendentes.
Desafio
FácilVamos construir um gerenciador de conexões que demonstra o RAII ao lidar automaticamente com o ciclo de vida de conexões do tipo rede. Quando uma conexão é criada, ela deve "abrir" e, quando sair do escopo, deve "fechar" automaticamente — sem a necessidade de limpeza manual!
Você criará dois arquivos para organizar seu código:
Connection.h: Defina uma classeConnectionque gerencia 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 rastrear o estado da conexão - Um construtor que recebe um ID de conexão, define
isOpencomo true e imprime"Opening connection: <id>" - Um destruidor que verifica se a conexão está aberta, fecha-a definindo
isOpencomo false e imprime"Closing connection: <id>" - Um método
send(string message)que imprime"[<id>] Sending: <message>"se a conexão estiver aberta - Um método
getId()que retorna 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. Então:- Crie um escopo usando chaves
{ } - Dentro desse escopo, crie um objeto
Connectionna pilha com o ID de entrada - Use a conexão para enviar a mensagem de entrada
- Deixe o escopo terminar (a conexão deve fechar 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 destruidor cuida disso automaticamente quando o objeto sai do escopo. Esse padrão evita vazamentos de recursos mesmo que algo inesperado aconteça em seu código.
Inclua seu arquivo de cabeçalho no main.cpp usando #include "Connection.h".
Folha de consulta
RAII (Resource Acquisition Is Initialization) é um idioma de C++ onde o gerenciamento de recursos está vinculado ao tempo de vida do objeto. Os recursos são adquiridos no construtor e liberados no destrutor.
Quando um objeto sai de escopo, seu destrutor libera automaticamente os recursos, garantindo a limpeza mesmo que ocorram exceções:
class FileHandler {
std::FILE* file;
public:
FileHandler(const char* filename) {
file = std::fopen(filename, "r"); // Adquire o recurso
}
~FileHandler() {
if (file) std::fclose(file); // Libera o recurso
}
};RAII garante a limpeza automática:
void processFile() {
FileHandler handler("data.txt"); // Recurso adquirido
// Trabalha com o arquivo...
// Se uma exceção for lançada, o destrutor ainda será executado!
} // Recurso liberado automaticamenteSmart pointers como unique_ptr são exemplos de RAII. Eles adquirem memória heap no construtor e a deletam no destrutor.
O RAII se aplica a qualquer recurso: memória, handles de arquivo, conexões de rede, mutexes ou conexões de banco de dados. Ele garante uma limpeza determinística e elimina bugs como vazamentos e handles pendentes (dangling handles).
Experimente você mesmo
#include <iostream>
#include <string>
#include "Connection.h"
using namespace std;
int main() {
string connectionId;
string message;
// Ler a entrada
cin >> connectionId;
cin.ignore();
getline(cin, message);
// TODO: Criar um escopo usando chaves { }
// Dentro do escopo:
// - Criar um objeto Connection na stack com connectionId
// - Usar a conexão para enviar a mensagem
// Deixar o escopo terminar (o destrutor será chamado automaticamente)
// TODO: Após o fim do escopo, imprimir "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 OOP
Arquivos ExternosBuild e Compilação em C++Arquivos Header e SourceNamespaces e EscopoIntrodução a OOP em C++Classes vs ObjetosO Ponteiro 'this'Métodos (Funções Membro)Atributos (Membros de Dados)Básico de Ctors e DtorsRecapitulação - Calculadora Simples4Propriedades de Classe
Membros de Instância vs EstáticosGetters e SettersFunções de Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRecapitulação - Gerenciador de Conta Bancária7Herança
Herança BásicaNíveis de Acesso na HerançaOrdem de Chamada de Ctor e DtorSobrescrita de MétodosFunções Virtuais e VTableHerança MúltiplaHerança VirtualRecapitulação - Hierarquia de Funcionários2Gerenciamento de Memória
Memória Stack vs HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Smart Pointers em C++RAII em C++Recapitulação - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de Acesso em C++Especificadores de Acesso em DetalhesOcultação de InformaçãoStruct vs ClassClasses Aninhadas e InternasRecapitulação - Sistema de Registros de Alunos8Polimorfismo
Polimorfismo de Compilação vs Tempo de ExecuçãoSobrecarga de FunçõesFunções Virtuais RevisitadasFunções Virtuais PurasClasses AbstratasDesign de Interfaces em C++Dynamic Casting e RTTIRecapitulação - Calculadora de Formas3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentaçãoListas de Inicialização do ConstrutorConstrutores DelegadosMergulho Profundo em DestrutoresRegra dos Três / Cinco / ZeroRecapitulação - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de StreamSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçãoTemplates de ClasseEspecialização de TemplatesTemplates VariádicosFundamentos de SFINAE e Type TraitsRecapitulação - Container Genérico