2012-05-25 10 views
6
namespace QuantLib { 

    //! Base error class 
    class Error : public std::exception { 
     public: 
     /*! The explicit use of this constructor is not advised. 
      Use the QL_FAIL macro instead. 
     */ 
     Error(const std::string& file, 
       long line, 
       const std::string& functionName, 
       const std::string& message = ""); 
     /*! the automatically generated destructor would 
      not have the throw specifier. 
     */ 
     ~Error() throw() {} 
     //! returns the error message. 
     const char* what() const throw(); 
     private: 
     boost::shared_ptr<std::string> message_; 
    }; 

} 

Como puede ver a través del comentario, el destructor de la clase Error proporciona explícitamente una implementación vacía con especificador de no-tiro.¿Deberíamos proporcionar un destructor con un especificador de no-tiro?

Pregunta: ¿Es esto necesario? ¿O es una buena práctica comparar para permitir que el compilador genere un destructor implícito?

+0

Tuve que agregar un destructor de tiro no a mi clase de excepción que se derivó de std :: exception para eliminar una advertencia o error que gcc emitió cuando no había proporcionado uno. No le gustó que la clase derivada no tuviera la misma especificación de no-throw que la clase base. –

+1

* Si * decides hacer esto, utilizaría 'noexcept' en lugar de' throw() ', si es posible. Las especificaciones de excepciones dinámicas (incluido 'throw()', al menos tal como yo lo leo) están en desuso (aunque si su compilador no está preparado para el rapé, es posible que no pueda hacerlo). –

Respuesta

8

En C++ 11, los destructores son implícitamente throw() (a menos que cualquier miembro o base del tipo tenga un destructor con una especificación de excepción diferente) por lo que si está compilando en modo C++ 11 no es necesario.

Si está en C++ 03, es posible que desee agregarlo, pero si tendrá un efecto o no, está muy definida la implementación ... Ahora, para fines de documentación, es posible que desee agregarlo, pero de nuevo , se asume comúnmente que los destructores no tiran.

+0

Creo que eso no es exacto sobre C++ 11. – bames53

+0

En C++ 11, un dtor tiene implícitamente una especificación de excepción que es básicamente la unión de cualquier cosa lanzada por cualquier cosa que llame directamente. No es bueno solo si no llama a nada que arroje. [Al menos creo que esa es la intención - la redacción es un poco desordenada, por lo que es al menos discutible autocontradictorio en este momento]. –

+3

Repasé esta parte del estándar con un compañero de trabajo hace unas semanas, y el problema es que la especificación de excepción (si no se proporciona ninguna para el destructor) sería la de un destructor implícitamente declarado, que a su vez es la unión de las especificaciones de excepción de todas las funciones que llamaría la * definición implícita * de ese destructor, que son los destructores de todos los miembros y bases. Nuestro entendimiento en ese momento es que '~ Error() {throw 1; F(); } 'tendría una especificación de excepción' noexcept (true) 'incluso si' f' arroja ... –

4

Depende de lo que piense throw() medio.

Lo que realmente significa de acuerdo con la norma es "poner código adicional en cada llamada a esta función si es necesario, o en la función en sí, para asegurar que si esta función arroja la excepción se detecta y se llama std::unexpected" .

Determinados compiladores lo implementaron para indicar "optimizar las llamadas a esta función en el supuesto de que no se lanzarán", pero (en violación del estándar) no implementaron la verificación de tiempo de ejecución.

Por lo tanto, agregarlo a un destructor (que sin duda no debería tirar) a (pero en la práctica podría no) agregar una verificación de tiempo de ejecución que nunca debería activarse y, por lo tanto, podría ayudar a depurar el código. Puede o no permitir una optimización.

3

destructores siempre tienen implícitamente especificaciones de excepción:

[class.dtor] 12.4 p3

Una declaración de un destructor que no tiene una excepción de especificación se considera implícitamente a tener la misma excepción- especificación como una declaración implícita (15.4).

[except.spec] 15,4 p14

Una declarado implícitamente función miembro especial (Cláusula 12) tendrá una excepción de especificación. Si f es un constructor predeterminado declarado implícitamente, constructor de copia, mover constructor, destructor, operador de asignación de copia o operador de asignación de movimiento, su especificación de excepción implícita especifica el ID de tipo T si y solo si T está permitido por la especificación de excepción de una función invocada directamente por la definición implícita de f; f permitirá todas las excepciones si cualquier función que invoca directamente permite todas las excepciones, y f no permitirá excepciones si cada función que invoca directamente no permite excepciones.

Así que, no, no es necesario que utilice una especificación de excepción.


En destructores definidos por el usuario 03 C++ no tienen una especificación de excepción implícita, por lo que si lo hace definir su propio destructor no se puede confiar en el compilador para agregar automáticamente la especificación de excepción apropiado. Pero los destructores declarados implícitamente tienen la misma especificación de excepción implícita que en C++ 11.

+0

@SteveJessop: La primera cita (§12.4/3) es nueva en C++ 11. En C++ 03, la segunda cita se numera §15.4/13, pero (creo) tiene la misma redacción. –

Cuestiones relacionadas