Pregunta

En C++, se puede especificar que una función puede o no puede lanzar una excepción por el uso de una excepción especificador.Por ejemplo:

void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type

Estoy dudoso acerca de la realidad utilizando debido a lo siguiente:

  1. El compilador no realmente hacer valer la excepción de especificadores de alguna manera rigurosa, por lo que los beneficios no son grandes.Idealmente, usted desea conseguir un error de compilación.
  2. Si una función infringe una excepción especificador, creo que el comportamiento estándar es para terminar el programa.
  3. En VS.Net, se trata de tiro(X) como el tiro(...), por lo que la adhesión a la norma no es fuerte.

¿Crees excepción especificadores se debe usar?
Por favor responder con "sí" o "no" y ofrecer algunas razones para justificar su respuesta.

¿Fue útil?

Solución

No.

Aquí hay varios ejemplos de por qué:

  1. Código de la plantilla es imposible escribir con excepción de las especificaciones,

    template<class T>
    void f( T k )
    {
         T x( k );
         x.x();
    }
    

    Las copias pueden producir, el paso de parámetros podría lanzar, y x() podría arrojar alguna excepción desconocida.

  2. Excepción-especificaciones tienden a prohibir la extensibilidad.

    virtual void open() throw( FileNotFound );
    

    podría convertirse en

    virtual void open() throw( FileNotFound, SocketNotReady, InterprocessObjectNotImplemented, HardwareUnresponsive );
    

    Usted realmente puede escribir como

    throw( ... )
    

    La primera no es extensible, el segundo es faraónico y la tercera es realmente lo que se quiere decir cuando escribe que las funciones virtuales.

  3. Código de la herencia

    Al escribir el código que se basa en otra biblioteca, usted realmente no sabe lo que se puede hacer cuando algo sale terriblemente mal.

    int lib_f();
    
    void g() throw( k_too_small_exception )
    { 
       int k = lib_f();
       if( k < 0 ) throw k_too_small_exception();
    }
    

    g terminará, cuando lib_f() a los tiros.Este es (en la mayoría de los casos) no es lo que realmente quieres. std::terminate() nunca debe ser llamado.Siempre es mejor dejar que la aplicación se bloquee con una excepción no controlada, a partir de la cual se puede recuperar una pila de seguimiento, que en silencio/violentamente morir.

  4. Escribir código que devuelve errores comunes y lanza en ocasiones excepcionales.

    Error e = open( "bla.txt" );
    if( e == FileNotFound )
        MessageUser( "File bla.txt not found" );
    if( e == AccessDenied )
        MessageUser( "Failed to open bla.txt, because we don't have read rights ..." );
    if( e != Success )
        MessageUser( "Failed due to some other error, error code = " + itoa( e ) );
    
    try
    {
       std::vector<TObj> k( 1000 );
       // ...
    }
    catch( const bad_alloc& b )
    { 
       MessageUser( "out of memory, exiting process" );
       throw;
    }
    

Sin embargo, cuando la biblioteca apenas lanza su propia excepciones, puede utilizar excepción de las especificaciones del estado de su intención.

Otros consejos

Evitar excepción de las especificaciones en C++.Las razones que dan en tu pregunta son un buen inicio para qué.

Ver Herb Sutter del "Un Pragmático Vistazo a Excepción de las Especificaciones".

Creo que la forma estándar a excepción de convenio (en C++)
Excepción especificadores fueron un experimento en el estándar de C++ que en su mayoría fracasaron.
Con la excepción de que el no tirar el especificador es útil, pero también debe agregar la correspondiente try catch block internamente para asegurarse de que el código coincide con el especificador.Herb Sutter tiene una página sobre el tema. Gotch 82

Además creo que vale la pena describir de Excepción de Garantías.

Estos son, básicamente, documentación sobre cómo el estado de un objeto se ve afectado por las excepciones de escapar de un método en el objeto.Por desgracia no son forzada, o de lo contrario, mencionado por el compilador.
Impulsar y Excepciones

De Excepción De Garantías

No Hay Garantía De:

No hay garantía sobre el estado del objeto después de una excepción que se escapa de un método
En estas situaciones, el objeto ya no debe ser utilizado.

Garantía Básica:

En casi todas las situaciones, esta debería ser la garantía mínima de un método proporciona.
Esto garantiza que el objeto del estado es bien definido y puede todavía ser utilizado constantemente.

Fuerte Garantía:(aka Transaccional de Garantía)

Esto garantiza que el método se completa con éxito
O se producirá una Excepción y los objetos de estado no va a cambiar.

No Tirar De Garantía:

El método garantiza que no se permiten excepciones para propagar fuera del método.
Todos los destructores deben hacer de esta garantía.
| N. B.Si una excepción se escapa de un destructor, mientras que una excepción es ya la propagación de
| la aplicación terminará

gcc se emiten advertencias cuando se infringen excepción de las especificaciones.Yo lo que hago es utilizar macros para utilizar la excepción especificaciones sólo en una "pelusa" modo de compilar expresamente para la comprobación para asegurarse de que las excepciones de acuerdo con mi documentación.

La única útil excepción especificador es "throw()", como en "no tirar".

No.Si usted los usa y se produce una excepción que no se especifica, ya sea por su código o el código de llamada por su código, a continuación, el comportamiento predeterminado es de inmediato terminar su programa.

También, yo creo que su uso ha quedado obsoleto en el actual borrador de la de C++0x estándar.

Excepción de las especificaciones no son maravillosamente herramientas útiles en C++.Sin embargo, hay /es/ un buen uso de ellos, si se combina con std::inesperado.

Lo que yo hago en algunos proyectos es el código con excepción de las especificaciones y, a continuación, llamar a set_unexpected() con una función que va a lanzar una excepción especial de mi propio diseño.Esta excepción, en la construcción, se presenta una traza (en una plataforma de manera específica) y se deriva de std::bad_exception (para permitir que se propaguen si se desea).Si se hace un terminate() la llamada, como habitualmente lo hace, la traza se imprime por lo que() (así como el original de excepción que la causó;no es difícil encontrar que) y por lo tanto, obtener información de donde mi contrato fue violado, tal como lo inesperado de la biblioteca se produjo una excepción.

Si yo hago esto, yo no permitir la propagación de la biblioteca de excepciones (excepto sexual) y se derivan todos mis excepciones de std::excepción.Si una biblioteca decide a lanzar, voy a capturar y convertir en mi propia jerarquía, lo que para mí siempre el control del código.Plantilla de funciones que llaman a funciones dependientes deben evitar excepción de las especificaciones, por razones obvias;pero es raro tener una función de plantilla de la interfaz con el código de la biblioteca de todos modos (y algunas bibliotecas realmente el uso de plantillas de una manera útil).

Si estás escribiendo código que será utilizado por las personas que prefieren mirar a la declaración de la función de comentarios alrededor de él, entonces una especificación que les diga que las excepciones que se podría coger.

De lo contrario, no me parece especialmente útil para el uso de cualquier cosa pero throw() para indicar que no lanzar ninguna excepción.

Un "throw()" es una especificación que permite al compilador para realizar algunas optimizaciones al hacer el código de análisis de flujo si se sabe que la función nunca será lanzar una excepción (o, al menos, las promesas nunca lanzar una excepción).Larry Osterman habla brevemente aquí:

http://blogs.msdn.com/larryosterman/archive/2006/03/22/558390.aspx

Generalmente yo no los uso excepción especificadores.Sin embargo, en casos donde, si de cualquier otra excepción iban a venir de la función en cuestión que el programa iba a ser definitivamente incapaz de correcto, que puede ser útil.En todos los casos, asegúrese de documentar claramente qué excepciones se podía esperar de esa función.

Sí, el comportamiento esperado de un no especificado excepción de una función con excepción de los especificadores es llamar a terminate().

Yo también tenga en cuenta que Scott Meyers aborda este tema en Más Eficaz de C++.Su Efectivo de C++ y Más Eficaz de C++ son muy recomendables los libros.

Sí, si usted está en la documentación interna.O quizá la redacción de una biblioteca que otros van a utilizar, por lo que se puede decir lo que sucede sin la consulta de la documentación.Tirar o no tirar pueden ser considerados parte de la API, casi como el valor de retorno.

Estoy de acuerdo, ellos no son muy útiles para hacer cumplir la corrección de estilo del Java en el compilador, pero es mejor que nada o enseres comentarios.

Pueden ser útiles para la unidad de pruebas, de manera que al escribir las pruebas saber qué esperar de la función de proyección cuando se produce un error, pero no hay ninguna aplicación que las rodean en el compilador.Creo que son extra de código que no es necesario en C++.Que cada vez que usted elija todas las que usted debe estar seguro es de que siga el mismo estándar de codificación de todo el proyecto y los miembros del equipo por lo que el código sigue siendo legible.

Desde el artículo:

http://www.boost.org/community/exception_safety.html

"Es bien conocido por ser imposible escribir una excepción-seguro generic contenedor". Esta afirmación se oye a menudo con referencia a un artículo de Tom Cargill [4] en el que se explora el problema de excepción-la seguridad de una genérico plantilla de pila.En su el artículo, Cargill plantea muchas útil las preguntas, pero desafortunadamente no presentar una solución a su problema.1 concluye con la sugerencia de que un la solución no puede ser posible.Por desgracia, su artículo fue leído por muchos como "prueba" de que la especulación.Desde que se publicó no han sido muchos ejemplos de excepción-caja de seguridad componentes genéricos, entre ellos el de C++ la biblioteca estándar de los contenedores.

Y, de hecho, no puedo pensar en maneras de hacer las clases de plantilla excepción segura.A menos que usted no tiene control sobre todas las sub-clases, a continuación, usted puede tener un problema de todos modos.Para ello se podría crear typedefs en sus clases que definen las excepciones lanzadas por varias clases de plantilla.Esto creo que el problema es, como siempre, sujetándolo a posteriori, como se opuso a que el diseño desde el principio, y creo que es esta sobrecarga, que es el verdadero obstáculo.

Excepción especificaciones = basura, pregunte a cualquier desarrollador Java con más de 30 años

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top