2012-10-04 49 views
6

Duplicar posibles:
How to clean initialized resources if exception thrown from constructor in c++¿Cómo manejo adecuadamente las excepciones en los constructores?

¿Cómo manejo excepción en constructores si estoy creando 6 objetos y los objetos crear 5 objeto y produce un error al crear el sexto uno?

Gracias.

+3

¿Qué tal enlace, que Als le da aquí http://stackoverflow.com/questions/12723492/how-to-clean-initialized-resources-if-exception-thrown-from-constructor-in-c? ¿Este miembro miembros se opone? – ForEveR

+0

¿Qué manejo necesitas? Normalmente, simplemente permitiría que la excepción se propagara, de modo que los primeros 5 objetos se destruyan limpiamente. Algún contexto más sería útil – jalf

+0

RAII. (Http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) – ScaryAardvark

Respuesta

1

Cuando se lanza una excepción en el constructor, se destruyen todos los subobjetos completamente construidos. Dado que es una buena práctica tener destructores de objetos construidos para cuidar sus resoyrces, no es necesario hacer nada para estos subobjetos. Lo que queda es limpiar en el cuerpo del constructor que se está ejecutando actualmente cuando se lanza la excepción. Sin embargo, esto no es diferente de la limpieza en cualquier otra función.

Tenga en cuenta que la orden de destrucción es la inversa de la construcción. Es decir, la limpieza en el cuerpo comienza primero cuando todos los subobjetos no se destruyen. Luego se destruyen los miembros, luego las clases base no virtuales y finalmente las clases base virtuales.

3

El comportamiento habitual es simplemente permitir que la excepción se propague. Destructores para cualquier clase base y miembros completamente construidos se llamarán; si los primeros cinco objetos son miembros, serán correctamente destruidos.

El único caso donde puede ocurrir un problema es si los objetos de los que está hablando han sido dinámicamente asignados (usando new). Si eso es el caso: lo primero que debe preguntarse es por qué? ¿Por qué está asignando dinámicamente y no convirtiendo al objeto en un miembro concreto? En mi experiencia, tal necesidad es muy, muy rara, excepto en algunos casos especiales (por ejemplo, el idioma del firewall de compilación), en cuyo caso, normalmente será exactamente un objeto en la clase (por ejemplo, un puntero al objeto de implementación). En tales casos, no hay ningún problema, porque si falla el new de ese objeto, no se ha hecho nada más que necesite deshacer.

Si usted se encuentra en el caso excepcionalmente raro en el que realmente tiene que utilizar la asignación dinámica y tener más de un objeto tal (por ejemplo, porque tiene dos subobjetos cuales son polimórficas), a continuación, se Tendremos que asegurarnos de que cada una de las asignaciones esté envuelta en algún tipo de subobjeto (un puntero inteligente hará el truco); una vez que el primer subobjeto se ha construido con éxito, su destructor será llamado si el constructor falla en algún momento posterior.

1

En el "núcleo" de hacer frente a las excepciones es que prácticamente todo se debe limpiar a través de destructores. Por ejemplo, si "nuevo" un objeto obtienes un puntero "en bruto"; si se lanza una excepción en alguna parte, debe asegurarse de que este puntero sin formato esté correctamente "eliminado" d, pero asegúrese de no eliminar un puntero sin procesar que no se haya inicializado.

Por otro lado, si almacena ese puntero en std :: unique_ptr, no tiene que hacer nada; cuando se destruye el unique_ptr el objeto se elimina y la destrucción de objetos ocurre automáticamente: cuando el unique_ptr sale del alcance, el compilador invoca la limpieza, completamente invisible (por lo que no hay más desorden de código con toneladas de llamadas de limpieza) y automáticamente (por lo no más 'ouch, cuando se necesita ese camino raro que nadie realmente probó se olvida de la limpieza').

Lo mismo se puede aplicar a casi todos los recursos; hay "punteros automáticos" para objetos COM (como los utilizados en DirectX, por ejemplo), la mayoría de los marcos deberían darle un objeto tipo "cerradura de ámbito" para envolver mutexes (por lo que bloquea el mutex cuando se crea el objeto, y lo desbloquea cuando está destruido), y puede escribir pequeños envoltorios para manejar varios identificadores de Windows.

Básicamente, si pones toda tu limpieza en destructores, nunca tendrás que "intentar ... coger ... volver a tirar" solo para limpiar. Y los destructores de objetos "más grandes" a menudo serán muy simples, ya que prácticamente todos los objetos "contenidos" son limpiados automáticamente por sus destructores.