captura de excepción por puntero en C++


Encontré que hay tres maneras de atrapar una excepción, ¿cuáles son las diferencias?

1) capturas por valor;

2) capturas por referencia;

3) captura por puntero;

Solo sé que catch by value invocará dos copias del objeto, catch by reference invocará una. Entonces, ¿qué tal atrapar por puntero? Cuándo usar catch by pointer? Además de lanzar un objeto, puedo lanzar un puntero a un objeto como este?

class A {}

void f() {

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


}
Author: Gregory Pakosz, 2010-01-07

5 answers

La forma recomendada es lanzar por valor y atrapar por referencia .

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

Si realmente cree que debe lanzar un puntero, use un puntero inteligente como shared_ptr.

De todos modos, Herb Sutter y Alexei Alexandrescu lo explican muy bien en su libro de Estándares de Codificación C++ que parafraseé.

Ver Estándares de codificación de C++: Throw by Valor, Captura por referencia .

 71
Author: Gregory Pakosz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-07 19:30:37

Catch sigue las reglas normales de compatibilidad de asignación, es decir, si arroja un valor, puede capturarlo como valor o referencia, pero no como puntero; si arroja un puntero, solo puede capturarlo como 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, en general, seguir la regla tirar por valor, atrapar por referencia, como explicó Gregory.

 15
Author: oefe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-07 19:41:16

El MFC de Microsoft usa catch by pointer, pero creo que fue por compatibilidad con el compilador antes de que try and catch se implementara correctamente; originalmente usaron macros TRY and CATCH para simularlo. Cada excepción deriva de CException, que tiene un método para determinar si el objeto debe eliminarse.

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

 4
Author: Mark Ransom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-07 19:43:43

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

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

También está 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, intentar asignar su objeto de excepción fuera de esa tienda/montón libre agotada/corrupta generalmente no funcionará muy bien...

 2
Author: Jerry Coffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-07 19:50:41

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

Sin embargo, algunas bibliotecas (Boost.Graph hace esto, creo) use throw para pasar un valor devuelto al llamante desde una función profundamente recursiva; en una situación como esta, el valor devuelto puede ser un puntero, por lo que lanzar un puntero tendría sentido.

 1
Author: Collin Dauphinee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-07 19:36:24