Ir al contenido

RAII

De Wikipedia, la enciclopedia libre
Esta es una versión antigua de esta página, editada a las 15:18 15 abr 2010 por Wikante (discusión · contribs.). La dirección URL es un enlace permanente a esta versión, que puede ser diferente de la versión actual.

"Adquirir Recursos es Inicializar", a menudo referido por sus siglas en inglés RAII (de "Resource Acquisition Is Initialization"), es un popular patrón de diseño en varios lenguajes de programación orientados a objetos como C++, y Ada. La técnica fue inventada por Bjarne Stroustrup[1]​ para reservar y liberar recursos en C++. En este lenguaje, después de que se lance una excepción, el único código fuente que seguro que va a ser ejecutado son los destructores de objectos que residen en la pila. Por tanto los recursos necesitan ser gestionados con objetos adecuados. Los recursos son adquiridos durante la inicialización, cuando no hay posibilidad de que sean usados antes de ser disponibles, y liberados cuando se destruyan los mismos objetos, que se garantiza que sucede incluso cuando hay errores.

La técnica RAII es vital al escribir código C++ seguro frente a exepciones: para liberar recursos antes de permitir a las excepciones que se propaguen (para evitar fugas de memoria) el desarrollador puede escribir destructores apropiados una vez y ya está, ahorrándose escribir código de "limpieza" duplicado y disperso por el código fuente entre bloques de manejo de excepciones que pueden ser ejecutados o no.

A diferencia de la recolección de basura, RAII tiene las ventajas de: saber cuándo los objetos existen y saber cuándo no.

Ejemplo

La siguiente clase RAII permite un posterior uso fácil de algunas funciones C usadas para el manejo de archivos.

#include <cstdio>
#include <stdexcept> // Para poder usar std::runtime_error
class file {
public:
    file (const char* filename)
        : file_(std::fopen(filename, "w+")) {
        if (!file_) {
            throw std::runtime_error("error al abrir un archivo");
        }
    }

    ~file() {
        if (std::fclose(file_)) { 
            throw std::runtime_error("error al cerrar un archivo");
        }
    }

    void write (const char* str) {
        if (EOF == std::fputs(str, file_)) {
            throw std::runtime_error("error al escribir en un archivos");
        }
    }

private:
    std::FILE* file_;

    // Evitamos la copia y asignación, ya que no están implementadas.
    file (const file &);
    file & operator= (const file &);
};

La clase file puede ser usada así:

void example_usage() {
    file logfile("registro_de_incidencias.txt"); // Abrimos el archivo (estamos adquiriendo un recurso).
    logfile.write("¡Hola, registro!");
    // Continuamos usando el objeto logfile.
    // Podemos lanzar excepciones, usar la orden "return", "exit", etc. sin preocuparnos de cerrar el archivo;
    // debido a que el archivo se cierra automáticamente cuando se termina la vida de logfile.
}

References

  1. Stroustrup, Bjarne (1994). The Design and Evolution of C++. Addison-Wesley. ISBN 0-201-54330-3.