Menu
Coddy logo textTech

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 automaticamente

Smart 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.

challenge icon

Desafio

Fácil

Vamos 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 classe Connection que 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 isOpen como true e imprime "Opening connection: <id>"
    • Um destruidor que verifica se a conexão está aberta, fecha-a definindo isOpen como 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
  • 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 Connection na 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"

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 automaticamente

Smart 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;
}
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