2010-01-07 21 views
42

Encontré que hay tres formas de atrapar una excepción, ¿cuáles son las diferencias?excepción de captura por puntero en C++

1) coger por valor;

2) captura por referencia;

3) captura por puntero;

Solo sé que catch by value invocará dos copias del objeto, catch by reference invocará uno. Entonces, ¿qué hay de atrapar por puntero? ¿Cuándo usar la captura por puntero? Además de arrojar un objeto, ¿puedo arrojar un puntero a un objeto como este?

class A {} 

void f() { 

    A *p = new A(); 
     throw p; 


} 
+6

Usted puede __not__ atrapar una excepción con un puntero. Puede ver una excepción que pasa a ser un puntero. El problema es que A y A * son dos tipos completamente diferentes. Si arrojas un puntero a A, solo puedes capturar valor o referencia. Pero es un A * que está atrapando por valor o referencia no como A. –

Respuesta

70

La forma recomendada es tirar por valor y por referencia captura.

Su código de ejemplo arroja un puntero, lo cual es una mala idea, ya que tendría que administrar la memoria en el sitio de captura.

Si realmente siente que debe arrojar un puntero, use un puntero inteligente como shared_ptr.

De todos modos, Herb Sutter y Alexei Alexandrescu lo explican muy bien en su libro C++ Coding Standards que parafraseé.

Ver C++ Coding Standards: Throw by Value, Catch by Reference.

+12

Y si la razón por la que está arrojando es porque se ha quedado sin memoria, entonces tratar de asignar un nuevo objeto a arrojar no va a ayudar. –

+3

O bien arrojaría un puntero a A, o lanzaría std :: bad_alloc, según si se podría asignar A. Así que al menos arrojarías algo ... –

+0

He visto código como 'const std :: runtime_error err; throw err; '¿estoy en lo correcto asumiendo que esto no será capturado por referencia (sin conversión de' const std :: runtime_error & 'a' std :: runtime_error & ')? Esto, por lo tanto, será atrapado por el tiempo de ejecución y presumiblemente bloqueará el programa. ¿Estoy en lo cierto? –

1

No hay realmente un buen escenario para capturar/lanzar una excepción con un puntero. La semántica de C++ lo permite, pero no es terriblemente útil, ya que la mayoría de las veces lanzará una excepción temporal u objeto de cadena.

Sin embargo, algunas bibliotecas (Boost.Graph hace esto, creo) usan throw para pasar un valor de retorno a la persona que llama desde una función profundamente recursada; en una situación como esta, el valor de retorno puede ser un puntero, por lo que arrojar un puntero tendría sentido.

14

La captura sigue reglas de compatibilidad de asignación normal, es decir, si arroja un valor, puede tomarlo como valor o referencia, pero no como puntero; si arroja un puntero, puede atraparlo solo como un puntero (o referencia a un puntero ...).

Pero realmente no tiene sentido lanzar punteros, solo causará dolores de cabeza en el manejo de la memoria. Por lo tanto, debe seguir, en general, la regla arrojar por valor, capturar por referencia, como explica Gregory.

4

El MFC de Microsoft usa la captura por puntero, pero creo que fue por compatibilidad con el compilador antes de que try and catch se implementara correctamente; originalmente usaron las macros TRY y CATCH para simularlo. Cada excepción se deriva de CException, que tiene un método para determinar si el objeto necesita ser eliminado.

No lo recomendaría para ningún diseño de excepción moderno. La captura por referencia es el camino a seguir.

2

Si bien es posible lanzar esencialmente cualquier objeto de cualquier tipo, hay poco (si acaso) que ganar con esto. La asignación dinámica es útil principalmente cuando un objeto necesita tener una vida útil no encaja con la asignación automática, es decir, desea que su duración sea independiente del alcance del programa normal.

En el caso de un objeto de excepción, sin embargo, eso realmente no tiene mucho sentido. Normalmente, un objeto de excepción solo se usa dentro de un manejador de excepciones, y claramente quiere que se destruya cuando salga del (último) controlador para esa excepción.

También existe el hecho de que generalmente desea mantener el código de manejo de excepciones bastante simple. Solo por ejemplo, si está tratando de informar que la tienda/montón libre está agotada o corrupta, tratar de asignar su objeto de excepción a la tienda/montón gratuito agotado/corrupto generalmente no funcionará muy bien ...

Cuestiones relacionadas