2011-04-20 23 views
7

De acuerdo con the C++ FAQ, cuando uno arroja un objeto, se lanza utilizando el tipo estático de la expresión. Por lo tanto, si usted tiene:Justificación para arrojar tipos estáticos?

catch (some_exception const &e) { 
    // ... 
    throw e; // throws static type, possibly causing "slicing"; should just "throw;" instead 
} 

y e es realidad una referencia a alguna clase derivada de some_exception, lo anterior throw hará que el objeto que se va "rodajas" en silencio. Sí, sé que la respuesta correcta es simplemente throw;, pero la forma en que están las cosas parece ser una fuente innecesaria de confusión y errores.

¿Cuál es la razón de esto? ¿Por qué no desea arrojar por el tipo dinámico del objeto?

Respuesta

4

El "argumento" para throw es una expresión y es el tipo de expresión que determina el tipo de objeto de excepción lanzado. El tipo de expresión arrojada no necesariamente tiene que ser un tipo polimórfico, por lo que puede no haber una forma de determinar si la expresión realmente se refiere a un subobjeto de clase base de un tipo más derivado.

La regla más simple de "tipo de expresión" también significa que la implementación no tiene que determinar dinámicamente el tamaño y el tipo del objeto de excepción en tiempo de ejecución, lo que podría requerir la generación de código más complejo y menos eficiente para el manejo de excepciones . Si tuviera que hacer esto, representaría el único lugar en un idioma donde se requiere un constructor de copia para un tipo desconocido en el punto de llamada. Esto podría aumentar significativamente el costo de implementación.

9

Cuando throw algo, un objeto temporal se construye desde el operando de throw y ese objeto temporal es el objeto que se atrapa.

C++ no tiene soporte integrado para copiar objetos o crear objetos en función del tipo dinámico de una expresión, por lo que el objeto temporal es del tipo estático del operando.

+0

Pero si lo captas por referencia, parecería que simplemente podría volver a lanzar el mismo objeto sin hacer ninguna copia (como lo hace "throw"). –

+4

Luego 'throw x;' se comporta de manera diferente dependiendo de su operando y de si aparece en un bloque 'catch'. El beneficio de tener 'throw x;' distinto de 'throw;' es que el comportamiento de 'throw x;' es siempre el mismo (se hace una copia y esa copia es la que se captura), pero usted todavía tiene la capacidad de vuelva a lanzar la excepción actual si así lo desea. [Probablemente debería tener en cuenta que en algunas circunstancias la copia puede ser eliminada, pero solo si hacerlo no cambia el comportamiento del programa, aparte de la convocatoria de constructores y destructores.] –

+0

+1 Buena explicación. :-) – Nawaz

0

Considere que podemos tener referencias a objetos donde se puede copiar el tipo estático de la referencia, pero no el tipo dinámico del objeto.

struct foo {}; 

struct ncfoo : foo 
{ 
private: 
    ncfoo(ncfoo const&) {} 
}; 

ncfoo g_ncfoo; 

void fun() 
{ 
    foo& ref = g_ncfoo; 
    throw ref; // what should be thrown here? 
} 

Si dice que "en este caso sólo tirar del tipo estático", entonces, ¿cómo son las reglas exactas - ¿qué significa "en este caso" significa? Las referencias que acabamos de capturar son "relanzadas" sin copiar, todo lo demás se copia? Hm ...

Pero como defina la regla, todavía sería confuso. Lanzar by-reference llevaría a un comportamiento diferente, dependiendo de dónde obtuvimos esa referencia. Neh. C++ ya es bastante complicado y confuso :)

Cuestiones relacionadas