2010-04-26 16 views
5

Si un destructor arroja C++ durante el desenrollado de la pila causado por una excepción, el programa finaliza. (Es por eso que los destructores nunca deben tirar en C++.) Ejemplo:Lanzar una nueva excepción al lanzar una excepción antigua

struct Foo 
{ 
    ~Foo() 
    { 
     throw 2; // whoops, already throwing 1 at this point, let's terminate! 
    } 
}; 

int main() 
{ 
    Foo foo; 
    throw 1; 
} 

terminate called after throwing an instance of 'int' 

This application has requested the Runtime to terminate it in an unusual way. 
Please contact the application's support team for more information. 

Si se introduce un bloque finally en Java debido a una excepción en el bloque try correspondiente y que, finalmente, el bloque lanza una segunda excepción, la primera excepción es silenciosamente tragado. Ejemplo:

public static void foo() throws Exception 
{ 
    try 
    { 
     throw new Exception("first"); 
    } 
    finally 
    { 
     throw new Exception("second"); 
    } 
} 

public static void main(String[] args) 
{ 
    try 
    { 
     foo(); 
    } 
    catch (Exception e) 
    { 
     System.out.println(e.getMessage()); // prints "second" 
    } 
} 

Esta pregunta pasó por mi mente: ¿Podría un lenguaje de programación manejar múltiples excepciones siendo lanzado al mismo tiempo? ¿Sería eso útil? ¿Alguna vez has perdido esa habilidad? ¿Hay un lenguaje que ya sea compatible con esto? ¿Hay alguna experiencia con este enfoque?

¿Alguna idea?

+7

Acabas de hacer que mi cerebro arroje una excepción –

+1

Interesante pregunta. Supongo que al "manejar una excepción" se refiere específicamente a "desenrollar la pila debido a una excepción", no a "ejecutar código desde un bloque catch". Esto último lo llamaría "manejo de una excepción", pero como se ha localizado un controlador, puede lanzar una excepción desde allí (al menos en C++). –

+0

@Nick Tienes razón, edité el título.Si conoce uno mejor, siéntase libre de cambiarlo de nuevo ;-) – fredoverflow

Respuesta

5

Piense en términos de control de flujo. Las excepciones son fundamentalmente lujosas setjmp/longjmp o setcc/callcc de todos modos.El objeto de excepción se usa para seleccionar un lugar en particular al que ir, como una dirección. El manejador de excepciones simplemente recurre en la excepción actual, longjmp ing hasta que se maneje.

Manejar dos excepciones a la vez es simplemente una cuestión de agruparlas en una, de modo que el resultado produzca un control de flujo coherente. Puedo pensar en dos alternativas:

  • Combínalos en una excepción que no se puede atrapar. Esto equivaldría a desenrollar toda la pila e ignorar a todos los manipuladores. Esto crea el riesgo de una cascada de excepción que causa un comportamiento totalmente aleatorio.
  • De alguna manera construye su producto cartesiano. Sí claro.

La metodología C++ sirve bien para el interés de la previsibilidad.

0

Sí, es posible admitir un idioma lanzando múltiples excepciones a la vez; sin embargo, eso también significa que los programadores necesitan manejar múltiples excepciones a la vez, por lo que definitivamente hay una compensación. He oído hablar de idiomas que tienen esto, aunque tengo problemas para sacar la lista de la parte superior de mi cabeza; Creo que LINQ o PLINQ pueden ser uno de esos idiomas, pero no lo recuerdo del todo. De todos modos, hay diferentes formas en que se pueden lanzar múltiples excepciones ... una forma es usar el encadenamiento de excepciones, ya sea forzando una excepción a convertirse en la "causa" o "previamenteExcepciónPropuesta" de la otra, o embotellar todas las excepciones en una sola excepción que representa el hecho de que se han lanzado múltiples excepciones. Supongo que un lenguaje también podría introducir una cláusula de captura que le permite especificar múltiples tipos de excepción a la vez, aunque sería una opción de diseño deficiente, en mi humilde opinión, ya que el número de manipuladores es lo suficientemente grande como es, y eso daría como resultado una explosión de captar cláusulas solo para manejar cada combinación posible.

2

¿Podría un lenguaje de programación manejar múltiples excepciones? Claro, no veo por qué no. ¿Esto sería útil? No, yo diría que no lo será. El manejo y la reanudación de errores es muy difícil, ya que no veo cómo la adición de una explosión combinatoria al problema ayudaría a las cosas.

3

Puede encadenar excepciones. http://java.sun.com/docs/books/tutorial/essential/exceptions/chained.html

try { 

} catch (IOException e) { 
    throw new SampleException("Other IOException", e); 
} 

También puede tener un intento de captura dentro de su Conviene por último garantizar también.

try{ 
}catch(Exception e){ 
}finally{ 
    try{ 
     throw new SampleException("foo"); 
    }catch(Exception e){ 
    } 
} 

Editar:

También se pueden tener varias capturas. No creo que las múltiples excepciones sean una buena idea, porque una excepción ya es algo de lo que necesita recuperarse. La única razón por la que puedo pensar en más de una excepción es si la usas como parte de tu lógica (como múltiples devoluciones), lo que se desviaría del propósito original de la idea de la Excepción. Además, ¿cómo se pueden producir dos excepciones al mismo tiempo?

+0

Creo que C# también permite el encadenamiento. Me pregunto si C++ 0x permitirá el encadenamiento. –

+0

Esto está permitido en todos los C++. El problema de C++ establecido por OP no está relacionado. – Potatoswatter

0

C++ std :: exception_ptr le permite almacenar excepciones. Por lo tanto, debería ser posible incrustar excepciones en otras excepciones y darle la impresión de que tiene la pila en excepciones lanzadas. Esto podría ser útil si desea conocer la causa raíz de la excepción real.

+0

Esto se aplica a las excepciones lanzadas dentro de un bloque 'catch'. Las excepciones arrojadas por los destructores durante el desenrollado son una bestia diferente. – Potatoswatter

+0

Lo sé. Pero la pregunta no está relacionada con esto, es solo una introducción a la pregunta final. –

0

Una situación en la que múltiples excepciones lanzadas en paralelo puede ser útil, es la unidad de pruebas con JUnit:

  • Si una prueba falla, se produce una excepción (ya sea producido por código de bajo prueba o una afirmación).
  • Cada método @After se invoca después de la prueba, si la prueba falla o si tiene éxito.
  • Si falla un método After, se lanza otra excepción.
  • Solo la excepción arrojada en el método After se muestra en mi IDE (Eclipse) para el resultado de la prueba.

sé que JUnit notifica a sus oyentes de prueba sobre dos excepciones, y cuando la depuración de una prueba en Eclipse que se puede ver la primera excepción que aparece en la vista JUnit, sólo para ser reemplazado por la segunda excepción poco después.

Este problema probablemente debería resolverse haciendo que Eclipse recuerde todas las notificaciones para una prueba determinada, no solo la última. Tener "excepciones paralelas", donde la excepción de finally no se traga la del try, resolvería este problema también.

0

Si lo piensa bien, la situación que ha descrito tiene Exception("First") como la causa raíz de Exception("second"), conceptualmente. Lo más útil para el usuario sería obtener un volcado de pila mostrando una cadena en ese orden ...

0

En las plataformas administradas, puedo pensar en situaciones en las que podría ser útil tener un triturador para "elevar" un excepción a algo que es más fuerte, pero no totalmente fatal para una aplicación. Por ejemplo, un triturador de un objeto "comando" podría intentar desenrollar el estado de su conexión asociada para cancelar cualquier comando realizado parcialmente. Si eso funciona, el código subyacente puede intentar hacer otras cosas con la conexión. Si el intento de "cancelar" no funciona, la excepción probablemente se propague al nivel donde la conexión se hubiera destruido. En tal caso, puede ser útil que la excepción contenga una "excepción interna", aunque la única forma que conozco de lograr eso sería intentar el desenrollado en un bloque catch en lugar de un bloque "finally".

Cuestiones relacionadas