¿Qué se entiende por adquisición de recursos es inicialización (RAII)?

12 minutos de lectura

¿Que se entiende por adquisicion de recursos es inicializacion RAII
Juan

¿Qué se entiende por adquisición de recursos es inicialización (RAII)?

¿Que se entiende por adquisicion de recursos es inicializacion RAII
el_mandril

Es un nombre realmente terrible para un concepto increíblemente poderoso, y quizás una de las cosas principales que los desarrolladores de C++ pierden cuando cambian a otros lenguajes. Ha habido un poco de movimiento para tratar de cambiar el nombre de este concepto como Gestión de recursos limitada al alcanceaunque no parece haberse puesto de moda todavía.

Cuando decimos ‘Recurso’ no solo nos referimos a la memoria: podrían ser identificadores de archivos, sockets de red, identificadores de bases de datos, objetos GDI… En resumen, cosas de las que tenemos un suministro finito y por lo que debemos poder controlar su uso. El aspecto ‘limitado al alcance’ significa que la vida útil del objeto está vinculada al alcance de una variable, por lo que cuando la variable sale del alcance, el destructor liberará el recurso. Una propiedad muy útil de esto es que proporciona una mayor seguridad de excepción. Por ejemplo, compare esto:

RawResourceHandle* handle=createNewResource();
handle->performInvalidOperation();  // Oops, throws exception
...
deleteResource(handle); // oh dear, never gets called so the resource leaks

Con el RAII

class ManagedResourceHandle {
public:
   ManagedResourceHandle(RawResourceHandle* rawHandle_) : rawHandle(rawHandle_) {};
   ~ManagedResourceHandle() {delete rawHandle; }
   ... // omitted operator*, etc
private:
   RawResourceHandle* rawHandle;
};

ManagedResourceHandle handle(createNewResource());
handle->performInvalidOperation();

En este último caso, cuando se lanza la excepción y se deshace la pila, las variables locales se destruyen, lo que garantiza que nuestro recurso se limpie y no se filtre.

  • @the_mandrill: probé ideone.com/1Jjzuc este programa. Pero no hay llamada de destructor. El tomdalling.com/blog/software-design/… dice que C++ garantiza que se llamará al destructor de objetos en la pila, incluso si se lanza una excepción. Entonces, ¿por qué destructor no se ejecutó aquí? ¿Mi recurso se filtró o nunca se liberará o liberará?

    – Destructor

    20 de agosto de 2015 a las 16:40

  • Se lanza una excepción, pero no la detecta, por lo que la aplicación finaliza. Si ajusta con un intento { } catch () {} entonces funciona como se esperaba: ideone.com/xm2GR9

    – el_mandril

    21 de agosto de 2015 a las 10:41

  • No estoy muy seguro si Scope-Bound es la mejor opción de nombre aquí ya que los especificadores de clase de almacenamiento Juntos con el alcance determina la duración del almacenamiento de una entidad. Estrecharlo hecho al límite del alcance es quizás una simplificación útil, sin embargo, no es 100% preciso

    – Haz click en mi

    12 de abril de 2018 a las 8:53


  • pero como explicas RA is initialization en el nombre original? Lo que entiendo por RAII es que es responsabilidad de cada objeto encargarse de su eliminación una vez fuera del alcance. para mi no coincide con is initialization porque todo está relacionado con el destructor. Todavía estoy confundido por ese nombre idiomático.

    – ahora buey

    11 de noviembre de 2020 a las 12:49

  • “… cosas número 1 que los desarrolladores de C++ pierden…” ¿No es esto similar a probar con recursos en Java? Parece resolver el mismo problema y no veo ninguna ventaja o desventaja de RAII en comparación con la solución de Java.

    – marc.guenther

    17 de diciembre de 2021 a las 15:58

¿Que se entiende por adquisicion de recursos es inicializacion RAII
Péter Török

Este es un lenguaje de programación que significa brevemente que usted

  • encapsular un recurso en una clase (cuyo constructor generalmente, pero no necesariamente **, adquiere el recurso y su destructor siempre lo libera)
  • usar el recurso a través de una instancia local de la clase*
  • el recurso se libera automáticamente cuando el objeto queda fuera del alcance

Esto garantiza que pase lo que pase mientras el recurso está en uso, eventualmente se liberará (ya sea debido a un retorno normal, destrucción del objeto contenedor o lanzamiento de una excepción).

Es una buena práctica ampliamente utilizada en C++ porque, además de ser una forma segura de manejar los recursos, también hace que su código sea mucho más limpio, ya que no necesita mezclar el código de manejo de errores con la funcionalidad principal.

* Actualizar: “local” puede significar una variable local o una variable miembro no estática de una clase. En el último caso, la variable miembro se inicializa y destruye con su objeto propietario.

** Actualización2: como señaló @sbi, el recurso, aunque a menudo se asigna dentro del constructor, también se puede asignar fuera y pasar como un parámetro.

  • AFAIK, el acrónimo no implica que el objeto tenga que estar en una variable local (pila). Podría ser una variable miembro de otro objeto, por lo que cuando se destruye el objeto ‘retenedor’, el objeto miembro también se destruye y el recurso se libera. De hecho, creo que el acrónimo significa específicamente que no hay open()/close() métodos para inicializar y liberar el recurso, solo el constructor y el destructor, por lo que la ‘retención’ del recurso es solo el tiempo de vida del objeto, sin importar si ese tiempo de vida es manejado por el contexto (pila) o explícitamente (asignación dinámica)

    – Javier

    23 de febrero de 2010 a las 20:51

  • En realidad, nada dice que el recurso debe adquirirse en el constructor. Los flujos de archivos, las cadenas y otros contenedores hacen eso, pero el recurso también podría ser aprobado al constructor, como suele ser el caso con los punteros inteligentes. Dado que la suya es la respuesta más votada, es posible que desee solucionar esto.

    – sbi

    8 oct 2012 a las 20:59

  • No es un acrónimo, es una abreviatura. La mayoría de la gente del IIRC lo pronuncia “ar ey ay ay”, por lo que en realidad no califica para un acrónimo como say DARPA, que se pronuncia DARPA en lugar de deletrearse. Además, diría que RAII es un paradigma en lugar de un mero idioma.

    – dtech

    5 de agosto de 2013 a las 10:24

  • @Peter Torok: lo intenté ideone.com/1Jjzuc este programa. Pero no hay llamada de destructor. los tomdalling.com/blog/software-design/… dice que C++ garantiza que se llamará al destructor de objetos en la pila, incluso si se lanza una excepción. Entonces, ¿por qué destructor no se ejecutó aquí? ¿Mi recurso se filtró o nunca se liberará o liberará?

    – Destructor

    20 de agosto de 2015 a las 16:35

  • En ese ejemplo, la excepción no se detecta, por lo que el programa finaliza instantáneamente. Si detecta la excepción, se llama al destructor cuando se desenrolla la pila.

    – el_mandril

    12 de noviembre de 2020 a las 16:36

1647635354 398 ¿Que se entiende por adquisicion de recursos es inicializacion RAII
sbi

“RAII” significa “Adquisición de recursos es inicialización” y en realidad es un nombre bastante inapropiado, ya que no es un recurso adquisición (y la inicialización de un objeto) que le concierne, pero liberando el recurso (mediante destrucción de un objeto).
Pero RAII es el nombre que obtuvimos y se mantiene.

En esencia, el modismo presenta recursos encapsulados (trozos de memoria, archivos abiertos, mutexes desbloqueados, lo que sea) en objetos automáticos localesy hacer que el destructor de ese objeto libere el recurso cuando el objeto se destruye al final del ámbito al que pertenece:

{
  raii obj(acquire_resource());
  // ...
} // obj's dtor will call release_resource()

Por supuesto, los objetos no siempre son objetos automáticos locales. También podrían ser miembros de una clase:

class something {
private:
  raii obj_;  // will live and die with instances of the class
  // ... 
};

Si dichos objetos administran la memoria, a menudo se los denomina “punteros inteligentes”.

Hay muchas variaciones de esto. Por ejemplo, en los primeros fragmentos de código surge la pregunta de qué pasaría si alguien quisiera copiar obj. La salida más fácil sería simplemente prohibir la copia. std::unique_ptr<>un puntero inteligente para ser parte de la biblioteca estándar como se presenta en el próximo estándar de C++, hace esto.
Otro puntero tan inteligente, std::shared_ptr presenta “propiedad compartida” del recurso (un objeto asignado dinámicamente) que contiene. Es decir, se puede copiar libremente y todas las copias se refieren al mismo objeto. El puntero inteligente realiza un seguimiento de cuántas copias se refieren al mismo objeto y lo eliminará cuando se destruya la última.
Una tercera variante es presentada por std::auto_ptr que implementa una especie de semántica de movimiento: un objeto es propiedad de un solo puntero, e intentar copiar un objeto dará como resultado (a través de la piratería de sintaxis) la transferencia de propiedad del objeto al objetivo de la operación de copia.

  • std::auto_ptr es una versión obsoleta de std::unique_ptr. std::auto_ptr tipo de semántica de movimiento simulado tanto como fue posible en C ++ 98, std::unique_ptr utiliza la nueva semántica de movimiento de C++11. Se creó una nueva clase porque la semántica de movimiento de C++ 11 es más explícita (requiere std::move excepto de temporal) mientras que estaba predeterminado para cualquier copia de non-const en std::auto_ptr.

    – Jan Hudec

    5 de agosto de 2013 a las 9:40

  • @JiahaoCai: Una vez, hace muchos años (en Usenet), el propio Stroustrup lo dijo.

    – sbi

    20 de enero de 2020 a las 18:49

La vida útil de un objeto está determinada por su alcance. Sin embargo, a veces necesitamos, o es útil, crear un objeto que viva independientemente del ámbito donde fue creado. En C++, el operador new se utiliza para crear tal objeto. Y para destruir el objeto, el operador delete puede ser usado. Objetos creados por el operador new se asignan dinámicamente, es decir, se asignan en memoria dinámica (también llamada montón o tienda gratis). Entonces, un objeto que fue creado por new continuará existiendo hasta que se destruya explícitamente usando delete.

Algunos errores que pueden ocurrir al usar new y delete están:

  • objeto filtrado (o memoria): usando new asignar un objeto y olvidarse de delete el objeto.
  • Eliminación prematura (o referencia colgante): sosteniendo otro puntero a un objeto, delete el objeto, y luego use el otro puntero.
  • Eliminación doble: tratando de delete un objeto dos veces.

En general, se prefieren las variables con ámbito. Sin embargo, RAII se puede utilizar como una alternativa a new y delete hacer que un objeto viva independientemente de su alcance. Esta técnica consiste en llevar el puntero al objeto que se asignó en el montón y colocarlo en un objeto manejador/administrador. Este último tiene un destructor que se encargará de destruir el objeto. Esto garantizará que el objeto esté disponible para cualquier función que quiera acceder a él, y que el objeto se destruya cuando finalice la vida útil del manejar objeto finaliza, sin necesidad de una limpieza explícita.

Los ejemplos de la biblioteca estándar de C++ que usan RAII son std::string y std::vector.

Considere esta pieza de código:

void fn(const std::string& str)
{
    std::vector<char> vec;
    for (auto c : str)
        vec.push_back(c);
    // do something
}

cuando crea un vector y le empuja elementos, no le importa asignar y desasignar dichos elementos. El vector utiliza new para asignar espacio para sus elementos en el montón, y delete para liberar ese espacio. Usted, como usuario de vector, no se preocupa por los detalles de implementación y confiará en que vector no se filtre. En este caso, el vector es el manejar objeto de sus elementos

Otros ejemplos de la biblioteca estándar que usan RAII son std::shared_ptr, std::unique_ptry std::lock_guard.

Otro nombre para esta técnica es SBRMcorto para Gestión de recursos limitada al alcance.

1647635354 231 ¿Que se entiende por adquisicion de recursos es inicializacion RAII
dennis

El libro Programación en C++ con patrones de diseño revelados describe RAII como:

  1. Adquirir todos los recursos
  2. Uso de recursos
  3. Liberando recursos

Donde

  • Los recursos se implementan como clases, y todos los punteros tienen contenedores de clase a su alrededor (lo que los convierte en punteros inteligentes).

  • Los recursos se adquieren invocando a sus constructores y se liberan implícitamente (en orden inverso al de adquisición) invocando a sus destructores.

  • @Brandin Edité mi publicación para que los lectores se concentren en el contenido que importa, en lugar de debatir el área gris de la ley de derechos de autor de lo que constituye un uso legítimo.

    -Dennis

    29 mayo 2016 a las 13:33

1647635354 337 ¿Que se entiende por adquisicion de recursos es inicializacion RAII
mohamed moridi

Hay tres partes en una clase RAII:

  1. Se renuncia al recurso en el destructor.
  2. Las instancias de la clase se asignan en la pila
  3. El recurso se adquiere en el constructor. Esta parte es opcional, pero común.

RAII significa “Adquisición de recursos es inicialización”. La parte de “adquisición de recursos” de RAII es donde comienza algo que debe finalizar más tarde, como:

  1. Abriendo un archivo
  2. Asignando algo de memoria
  3. Adquirir un candado

La parte “es inicialización” significa que la adquisición ocurre dentro del constructor de una clase.

https://www.tomdalling.com/blog/software-design/resource-acquisition-is-initialisation-raii-explained/

  • @Brandin Edité mi publicación para que los lectores se concentren en el contenido que importa, en lugar de debatir el área gris de la ley de derechos de autor de lo que constituye un uso justo.

    -Dennis

    29 mayo 2016 a las 13:33

1647635355 228 ¿Que se entiende por adquisicion de recursos es inicializacion RAII
Dmitri Pavlov

La gestión manual de la memoria es una pesadilla que los programadores han estado inventando formas de evitar desde la invención del compilador. Los lenguajes de programación con recolectores de basura hacen la vida más fácil, pero a costa del rendimiento. En este articulo – Eliminando al recolector de basura: The RAII Wayel ingeniero de Toptal Peter Goodspeed-Niklaus nos da un vistazo a la historia de los recolectores de basura y explica cómo las nociones de propiedad y préstamo pueden ayudar a eliminar a los recolectores de basura sin comprometer sus garantías de seguridad.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad