𝖂𝖎ƙ𝖎𝖊

Aquisição de Recurso é Inicialização

Aquisição de Recurso é Inicialização (conhecido pelo acrônimo RAII para o termo em língua inglesa Resource Acquisition Is Initialization) é um padrão de projeto de software para C++, D e Rust que combina a aquisição e liberação de recursos com inicialização e destruição de objetos.

Segundo a RAII, o uso de memória de um objeto inicia-se na sua declaração, e termina quando o objeto sai do escopo, seja porque a execução chegou ao final do bloco, ou porque uma exceção foi lançada. A liberação de memória é possível através do uso dos métodos destrutores da classe – a liberação da memória no destrutor garante que ela será realizada em qualquer caminho que o fluxo seguir, tornando o código seguro.[1][2]

Exemplo

A classe abaixo encapsula chamadas do gerenciamento de arquivos da biblioteca padrão do C usando RAII:

#include <cstdio>

class arquivo {
  std::FILE* m_ptrArquivo;

public:
  arquivo(const char* nomeArquivo)
    : m_ptrArquivo(std::fopen(nomeArquivo, "w+"))
  {
    if (!m_ptrArquivo)
      throw std::runtime_error("Erro ao abrir o arquivo.");
  }

  // atribuição e cópia não implementados, prevenindo o uso
  arquivo(const arquivo&) = delete;
  arquivo& operator=(const arquivo&) = delete;

  ~arquivo() {
    if (std::fclose(m_ptrArquivo) != 0) {
      // lida-se com erros do sistema de arquivos, fclose() pode falhar
    }
  }

  void escreve(const char* texto) {
    if (std::fputs(texto, m_ptrArquivo) == EOF)
      throw std::runtime_error("Erro ao escrever no arquivo.");
  }
};

Pode-se usar a classe acima da seguinte forma:

void exemplo_de_uso()
{
  // abre o arquivo (adquire e inicializa o recurso)
  arquivo arquivoLog("arquivoLog.txt");

  arquivo.escreve("Olá, log!");

  // continua usando arquivoLog...

  // lança exceções ou retorna sem se preocupar em fechar o recurso,
  // ele é fechado automaticamente quando seu escopo termina
}

A essência do idioma RAII é que a classe arquivo encapsula o gerenciamento do recurso FILE*, adquirindo e liberando automaticamente a memória, sem que seja necessário se preocupar com isso.

Uso e alternativas em outras linguagens

Objetos Java são destruídos automaticamente em tempos indeterminados pelo coletor de lixo. Os recursos então devem ser manualmente fechados pelo programador. O exemplo anterior deve ser escrito da seguinte maneira em Java:

void java_example() {
  // abre o arquivo (adquire o recurso)
  LogFile logfile = new LogFile("logfile.txt") ;
  
  try {
    logfile.write("hello logfile!") ;

    // continua usado logfile ...

  } finally {
    // fechamento explícito do recurso
    logfile.close();
  }
}

A responsabilidade de liberar o recurso recai sobre o programador em cada ponto onde o recurso é usado, e não de forma genérica em um local único.

Referências

  1. Bjarne Stroustrup (abril de 2001). «Exception Safety: Concepts and Techniques» (PDF). Consultado em 2 de setembro de 2007 
  2. Herb Sutter (1999). Exceptional C++. [S.l.]: Addison-Wesley. ISBN 0-201-61562-2 

talvez você goste