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
- ↑ Bjarne Stroustrup (abril de 2001). «Exception Safety: Concepts and Techniques» (PDF). Consultado em 2 de setembro de 2007
- ↑ Herb Sutter (1999). Exceptional C++. [S.l.]: Addison-Wesley. ISBN 0-201-61562-2
- Bjarne Stroustrup. «resource acquisition is initialization» (em inglês). Glossário de Bjarne Stroustrup