¿Qué es la adquisición de recursos es la inicialización (RAII)?

Tengo una comprensión básica de RAII. Me lo presentaron en el libro de Scott Meyers: C ++ efectivo: 55 formas específicas de mejorar sus programas y diseños. Es una técnica para garantizar la disponibilidad y eliminación de memoria asignada dinámicamente.

En lenguajes como C ++ donde la memoria es administrada por el programador, las técnicas RAII pueden ayudar a evitar el olvido de reclamar la memoria señalada por un puntero (por una llamada para delete ). Las técnicas RAII como los punteros inteligentes (puntero inteligente) envuelven un recurso asignado dinámicamente y eliminan el recurso asignado dinámicamente en el destructor. Dado que se creará una instancia de un puntero inteligente en la pila, se llama al destructor cuando sale del alcance.

La página de Wikipedia muestra cómo se usan, pero no cómo se pueden implementar. Aquí hay un ejemplo extremadamente simplificado. Tenga en cuenta que mi ejemplo está incompleto y no he escrito C ++ hace algún tiempo, pero la idea general es que algo administre la vida útil del recurso.

plantilla
clase SmartPointer
{
privado:
T * tPointer;
público:
SmartPointer (T t)
{
this-> tPointer = new T (t);
}

SmartPointer (T * const y tPointer)
{
this-> tPointer = tPointer;
}

~ SmartPointer ()
{
eliminar tPointer;
}
};

int main ()
{
SmartPointer smpt (nuevo int (10));
SmartPointer smpt2 (2.2);
}

Estoy seguro de que hay algunas respuestas más científicas y teóricas a lo que es RAII, pero este es el contexto con el que estoy familiarizado.

Así es como RAII – cppreference.com lo define (divulgación: escribí la mayor parte de esa página)

La adquisición de recursos es inicialización o RAII, es una técnica de programación C ++ (Preguntas frecuentes sobre estilo y técnica de C ++, isocpp / CppCoreGuidelines) que une el ciclo de vida de un recurso (memoria asignada, hilo de ejecución, socket abierto, archivo abierto, mutex bloqueado, conexión de base de datos —Cualquier cosa que exista en un suministro limitado) a la vida útil de un objeto.

RAII garantiza que el recurso esté disponible para cualquier función que pueda acceder al objeto (la disponibilidad del recurso es invariante de clase). También garantiza que todos los recursos se liberen cuando finalice la vida útil de su objeto de control, en orden inverso de adquisición. Del mismo modo, si falla la adquisición de recursos (el constructor sale con una excepción), todos los recursos adquiridos por cada miembro completamente construido y subobjeto base se liberan en orden inverso de inicialización. Esto aprovecha las características principales del lenguaje (duración del objeto, salida del alcance, orden de inicialización y desbobinado de la pila) para eliminar fugas de recursos y garantizar una seguridad de excepción. Otro nombre para esta técnica es Administración de recursos vinculados al alcance (SBRM), después del caso de uso básico donde la vida útil de un objeto RAII termina debido a la salida del alcance.

RAII se puede resumir de la siguiente manera:

  • encapsular cada recurso en una clase, donde
  • el constructor adquiere el recurso y establece todos los invariantes de clase o lanza una excepción si eso no se puede hacer,
  • el destructor libera el recurso y nunca lanza excepciones;
  • siempre use el recurso a través de una instancia de una clase RAII que
    • tiene una duración de almacenamiento automática o una vida útil temporal propiamente dicha, o
    • tiene una vida útil limitada por la vida útil de un objeto automático o temporal

    La semántica de movimiento permite transferir de forma segura la propiedad de recursos entre objetos, a través de ámbitos y dentro y fuera de subprocesos, mientras se mantiene la seguridad de los recursos.

    Las clases con funciones miembro open () / close (), lock () / unlock () o init () / copyFrom () / destroy () son ejemplos típicos de clases que no son RAII

    La idea de que un objeto no debe tener etapas separadas init / deinit, por lo que es imposible olvidar hacerlo. La asignación del objeto también debe realizar la inicialización, y la inicialización debe realizarse como parte de la desasignación. De esa manera, si tiene un objeto, sabe que está inicializado y listo para usar.

    La adquisición de recursos es la inicialización