c++ exception constructor raii

c++ - ¿Cómo funciona RAII cuando un constructor lanza una excepción?



exception (3)

Estás malinterpretando la primera cita. Eso no es difícil, ya que es confuso.

si se creó un objeto miembro con semántica RAII y se produce una excepción antes de que el constructor haya finalizado, se llamará a su destructor como parte del desenrollado de la pila.

Eso es lo que dice. Esto es lo que significó :

si se ha creado un objeto miembro con semántica RAII y ocurre una excepción en el objeto externo antes de que el constructor del objeto externo se haya completado, se llamará al destructor del objeto miembro como parte del desenrollamiento de la pila.

¿Ver la diferencia? La idea es que el objeto miembro haya completado su constructor, pero el tipo propietario no lo hizo. Se lanzó en algún lugar de su constructor (o un constructor de otro miembro que se inicializa después de ese). Esto hará que se llame al destructor de todos sus miembros (es decir, a todos los que completaron la construcción), pero no a su propio destructor.

Aquí hay un ejemplo:

class SomeType { InnerType val; public: SomeType() : val(...) { throw Exception; } };

Cuando creas una instancia de InnerType::InnerType llamará a InnerType::InnerType . Mientras no se lance, entrará en el constructor de SomeType . Cuando eso se lanza, causará que se destruya val , por lo que se llama InnerType::~InnerType .

Estoy aprendiendo sobre el lenguaje RAII en C ++, y cómo usar punteros inteligentes.

En mi lectura, he encontrado dos cosas que, para mí, parecen contradecirse entre sí.

Citado de http://www.hackcraft.net/raii/ :

... si se ha creado un objeto miembro con semántica RAII y se produce una excepción antes de que el constructor haya finalizado, se llamará a su destructor como parte del desenrollado de la pila. Por lo tanto, un objeto que controla múltiples recursos puede garantizar su limpieza incluso si no está completamente construido utilizando objetos miembros RAII.

Pero citado en http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10 :

Si un constructor lanza una excepción, el destructor del objeto no se ejecuta. Si su objeto ya ha hecho algo que debe deshacerse (como asignar algo de memoria, abrir un archivo o bloquear un semáforo), estas "cosas que deben deshacerse" deben ser recordadas por un miembro de datos dentro del objeto.

Y luego, la segunda fuente vinculada recomienda el uso de punteros inteligentes para tratar el problema de las cosas que ya estaban asignadas en el constructor.

Entonces, ¿qué sucede realmente en estos escenarios?


Estas dos afirmaciones no se contradicen entre sí, pero la primera tiene un lenguaje desafortunado. Cuando la construcción de algunos objetos arrojados, su deconstructor no será llamado, pero todos los objetos que sean propiedad de ese objeto serán destruidos por sus deconstructores individuales.

Así que con RAII y punteros inteligentes, los destructores para cualquier puntero miembro de un objeto se llamarán independientemente del destructor del objeto que debe. Los punteros sin procesar no liberan la memoria a la que apuntan y deben eliminarse manualmente. En caso de que el constructor del objeto propietario lance punteros en bruto, no será liberado. Esto no puede suceder con punteros inteligentes.


No hay contradicción aquí; hay solo una terminología confusa utilizada en diferentes contextos.

Si el constructor de un objeto lanza una excepción, entonces ocurre lo siguiente (asumiendo que la excepción es capturada):

  1. Todas las variables locales en el constructor tienen sus destructores invocados, liberando todos los recursos que han adquirido (si los hay).
  2. A todos los subobjetos directos del objeto cuyo constructor lanzó una excepción se invocarán sus destructores, liberando los recursos que hayan adquirido (si los hubiera).
  3. Todas las clases base del objeto cuyo constructor lanzó tendrán sus destructores invocados (ya que se construyeron completamente antes de que se ejecutara el constructor de la clase derivada)
  4. Se llevará a cabo una limpieza adicional de la persona que llama, etc.

Como resultado, cualquier recurso administrado por punteros inteligentes u otros objetos RAII que sean miembros de datos del objeto que se está destruyendo se eliminará, pero no se activará el código especializado para realizar la limpieza en el destructor del objeto.

¡Espero que esto ayude!