2011-01-19 22 views
26

En el próximo estándar C++ 0x, ¿qué ocurre cuando se lanza una excepción dentro/durante el constructor de movimientos?C++ Mover semántica y excepciones

¿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?

+0

Me pregunto si esto es como el destructor, donde es sólo una mala cosa si se produce una excepción. Supongo que en la mayoría de los casos puedes moverte sin hacer nada que pueda arrojar, ya que usualmente estás moviendo punteros alrededor ... – templatetypedef

+3

Entonces, lo que estás diciendo es que no debería haber una excepción. ser arrojado porque el estado de los miembros que se copian nunca se muta durante la operación de movimiento? –

+2

Sorta: es similar al argumento inductivo que usas para demostrar que 'swap' no puede lanzar. Como caso base, las primitivas de reasignación y copia nunca se lanzan. Como un paso inductivo, un constructor de movimiento para un objeto con algunos miembros de datos puede mover esos miembros de datos sin tirar (¡hipótesis inductiva!), y por lo tanto puede moverse solo sin tirar. Independientemente, sin embargo, todavía quiero saber cuál es la respuesta correcta a su pregunta. – templatetypedef

Respuesta

3

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 que se mueve, es lo mismo que tirar desde un ctor en el C++ actual: destruir las bases y 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 exigir a sus tipos asignador no tienen tirar ctors movimiento:

Tal construcción jugada del asignador no debe salir a través de una excepción. [N3225 §23.2p8]

Esto permite que los recipientes se muevan asignadores y usar esos asignadores para limpiar sus artículos en el caso de una excepción al mover o copiar elementos.

10

Creo que el comité de normas originalmente intentó hacer que los constructores no pudieran lanzar excepciones, pero (al menos hasta el día de hoy) descubrió que intentar aplicar eso tenía demasiados inconvenientes.

La propuesta N3050, "Permitir que Move Constructors for Throw (Rev 1)", se haya 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 en el blog de David Abrahams que discute los temas que N3050 pretendía abordar:

+0

Gracias por el artículo de David Abrahams :) –

+3

Sí, ¡yo también encontré todo el sitio de blog cpp-next bastante interesante en artículos dignos! –

2

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 excepción de garantía en absoluto (no es realmente un tipo ...pero puede suceder si no le preocupa el 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 no haberse deseado efectos secundarios, como el pago cobrado pero el comando no está registrado)
  • Strong Exception Guarantee: Todo o nada (como una transacción), o bien todo se hace bien o retrocedemos al anterior estado.
  • No Throw Exception Guarantee: Esto no tira, nunca, así que no se preocupe.

Al componer su función, por lo general, recupera 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.

W.r.su pregunta, se necesita al menos una Strong Exception Guarantee para que el objeto original no se toque si se produce una excepción.

Entonces, ¿qué ocurre si se lanza una excepción durante la construcción de movimientos? Depende de las garantías exhibidas por los objetos secundarios y la forma en que combinaba las llamadas ...

  1. Si se produce una excepción de un constructor, el objeto no se está construyendo y todos los subobjetos construidas se destruyen, en orden inverso. Esta regla también se aplica a un constructor de movimiento
  2. A menos que "ajuste" el 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 excepciones, esto significa que, por defecto, si todos los constructores subobjetos al menos con los Garantía Excepción básico, entonces su movimiento constructor también lo hará, sin ningún cuidado especial.

Sin embargo, incluso si los constructores todos los subobjetos cumplen con la garantía de Excepción fuerte, es poco probable que tenga éxito en tener su propio movimiento constructor de cumplir con él, porque éste es el mismo problema que el encadenamiento de las transacciones no produce una transacción.

Si sólo uno de los constructores subobjetos puede lanzar, y se encuentra con el Garantía Excepción fuerte, entonces su movimiento constructor de forma natural se reunirá con ella misma si inicializar el objeto de lanzar primero.

Espero que esto ayudó ... excepciones son una fiera de domesticar :)