C++ Move semántica y Excepciones
exception c++11 (3)
En el próximo estándar C ++ 0x, ¿qué sucede cuando se lanza una excepción dentro / durante el constructor de movimientos?
¿Permanecerá el objeto original? o son tanto el objeto original como el objeto de movimiento en un estado indefinido? ¿Cuáles son las garantías que ofrece el lenguaje?
Creo que el comité de estándares originalmente intentó hacer que los constructores no pudieran lanzar excepciones, pero (al menos hasta el día de hoy) descubrió que tratar de hacer cumplir eso tenía demasiados inconvenientes.
La propuesta N3050, "Permitir que Move Constructors tire (Rev 1)", se ha incorporado al borrador del estándar. Esencialmente, la propuesta agrega la capacidad de lanzar constructores de movimiento, pero no permitir movimientos de "lanzamiento" para ciertas operaciones donde se necesitaban fuertes garantías de excepción de seguridad (la biblioteca recurrirá a copiar el objeto si no se produce un movimiento de lanzamiento) t disponible).
Si marca un constructor de movimiento como non-throwing ( noexcept
) y se lanza una excepción, se llamará a std :: terminate ().
También podría valer la pena leer un artículo de blog de David Abrahams que discute los problemas que el N3050 intentaba abordar:
Depende del tipo del que se mueva. Es posible lanzar explícitamente una excepción, por supuesto, desde un cursor de movimiento, pero también invocar implícitamente una copia de un subobjeto desde un cursor de movimiento. Ese copiador puede hacer algo que pueda arrojar, como asignar memoria. Entonces, para el objeto fuente, la garantía mínima es que el valor original puede o no permanecer, pero aún debe estar en un estado destructible.
Para el objeto al que se mueve, es lo mismo que tirar desde un ctor en el C ++ actual: destruir las bases y los miembros construidos, ejecutar el manejador try de la función del ctor, si hay alguno, luego propagar la excepción. Los detalles están en N3225 §15.2p2.
En particular, tenga en cuenta que los contenedores requieren que sus tipos de asignadores no tengan dispositivos de desplazamiento de movimiento:
Dicha construcción de movimiento del asignador no debe salir a través de una excepción. [N3225 §23.2p8]
Esto permite que los contenedores muevan los asignadores y que utilicen esos asignadores para limpiar sus artículos en el caso de una excepción al mover o copiar artículos.
Su pregunta entonces equivale a una pregunta sobre garantías de excepción. Hay 3 tipos de garantías de excepciones (que se aplican a las funciones):
- Ninguna garantía de excepción (en realidad no es un tipo ... pero puede suceder si no se le da importancia al asunto)
- Garantía de excepción básica : técnicamente correcta, pero no Funcionalmente correcta (es decir, no se filtra ningún recurso, el programa terminará sin interrupción abrupta, pero puede tener efectos secundarios no deseados, como el pago cobrado pero el comando no registrado)
- Fuerte garantía de excepción : todo o nada (como una transacción), o bien todo se hace bien o retrocedemos al estado anterior.
- Garantía de excepción sin tiro : Esto no arroja, nunca, así que no se preocupe.
Cuando redactas tu función, usualmente recuperas las funciones existentes con sus propias garantías. Es difícil aumentar la garantía de excepción, es decir que generalmente está limitado por la garantía más débil utilizada.
Con su pregunta, se necesita al menos una fuerte garantía de excepción para que el objeto original quede intacto si se lanza una excepción.
Entonces, ¿qué sucede si se lanza una excepción durante la construcción de movimientos? Depende de las garantías exhibidas por los subobjetos y la forma en que combinaste las llamadas ...
- Si se lanza una excepción desde un constructor, el objeto no se está construyendo y todos los subobjetos construidos se destruyen, en orden inverso. Esta regla también es aplicable a un movimiento-constructor
- A menos que "envuelva" al constructor en una captura de prueba y de alguna manera restaure los objetos que se han movido, habrán perdido sus recursos. Tenga en cuenta que todavía deben estar en un estado destructible de todos modos, por lo que técnicamente el programa será correcto.
En términos de garantías de excepciones, significa que, por defecto, si todos los constructores de los subobjetos cumplen por lo menos la Garantía de excepción básica , el constructor de movimientos también lo hará, sin ningún cuidado especial.
Sin embargo, incluso si todos los constructores de los subobjetos cumplen con la garantía de excepción fuerte , es poco probable que consigas que tu propio constructor de movimientos lo resuelva: este es el mismo problema que el encadenamiento de transacciones no genera una transacción.
Si solo uno de los constructores de los subobjetos puede tirar, y cumple con la garantía de excepción fuerte , entonces el constructor de movimientos se encontrará con él por sí mismo si inicializas primero el objeto que arroja.
Espero que esto haya ayudado ... las excepciones son una bestia salvaje para domesticar :)