stroustrup - programa c++
Lo que dice el estándar de C++ acerca de perder el especificador de lanzamiento en el destructor predeterminado (2)
Evolucionó un poco en C ++ 11 [except.spec] :
5 / Si una función virtual tiene una especificación de excepción, todas las declaraciones, incluida la definición, de cualquier función que invalide esa función virtual en cualquier clase derivada solo permitirán excepciones permitidas por la especificación de excepción de la función virtual de clase base.
Por lo tanto, nunca se le permite especificar una especificación de excepción más flexible .
Sin embargo, este caso es complicado porque el propio compilador sintetiza el destructor.
En C ++ 03, creo que el Estándar no fue tan cuidadoso con ellos, y usted tuvo que escribirlos usted mismo, en C ++ 11, sin embargo, obtenemos:
14 / Una función miembro especial declarada implícitamente (Cláusula 12) tendrá una especificación de excepción. Si
f
es un constructor predeterminado implícitamente declarado, constructor de copia, constructor de movimiento, destructor, operador de asignación de copia u operador de asignación de movimiento, su especificación de excepción implícita especifica la id de tipoT
si y solo siT
es permitida por la especificación de excepción de una función invocada directamente por la definición implícita def
;f
permitirá todas las excepciones si cualquier función que invoca directamente permite todas las excepciones, yf
no permitirá excepciones si todas las funciones que invoca directamente no permite excepciones.
Donde el compilador generará la especificación de excepción del destructor para que coincida con lo que se puede lanzar desde las funciones que llama (es decir, los destructores de los atributos). Si esos destructores no lanzan, entonces generará un destructor noexcept
que satisfará la restricción de la clase base.
Nota: VS2005 es uno de los compiladores menos compatibles con el estándar que puede encontrar en la Tierra.
Tres compiladores diferentes muestran tres comportamientos diferentes al compilar este código:
class MyException : public std::exception
{
public:
MyException(std::string str) : m_str(str) {}
virtual const char * what() const throw () {return m_str.c_str(); }
protected:
std::string m_str;
};
Sun C ++ 5.8 parche 121017-22 2010/09/29: La función de advertencia MyException :: ~ MyException () puede lanzar solo las excepciones generadas por la función std :: exception :: ~ exception () que anula
g ++ 3.4.3: Error en el especificador de lanzamiento más flojo para `virtual MyException :: ~ MyException () ''
Visual Studio 2005: Es muy feliz (ni error ni advertencia)
class exception {
public:
exception () throw();
exception (const exception&) throw();
exception& operator= (const exception&) throw();
virtual ~exception() throw();
virtual const char* what() const throw();
}
Sé cuál es el problema y cómo puedo solucionarlo:
class MyException : public std::exception
{
public:
MyException(std::string str) : m_str(str) {}
virtual const char * what() const throw () {return m_str.c_str(); }
~MyException() throw() {} <------------ now it is fine!
protected:
std::string m_str;
};
Sin embargo, me pregunto qué dice la norma en una situación específica.
Hice otra pequeña prueba en Visual Studio 2005 y encontré algo que realmente me sorprendió:
struct Base
{
virtual int foo() const throw() { return 5; }
};
struct Derived : public Base
{
int foo() const { return 6; }
};
int main()
{
Base* b = new Derived;
std::cout << b->foo() << std::endl; //<-- this line print 6!!!
delete b;
}
La firma de las dos funciones son diferentes. ¿Cómo puede funcionar esto? Parece que Visual Studio 2005 ignora completamente la especificación de excepción.
struct Base
{
virtual int foo() const throw() { return 5; }
};
struct Derived : public Base
{
int foo() { return 6; } // I have removed the const keyword
// and the signature has changed
};
int main()
{
Base* b = new Derived;
std::cout << b->foo() << std::endl; // <-- this line print 5
delete b;
}
¿Es este estándar de C ++? ¿Hay alguna bandera mágica para establecer?
¿Qué pasa con VS2008 y VS2010?
Su programa está mal formado según el estándar de C ++ y, por lo tanto, demuestra un comportamiento que no se puede explicar dentro de los dominios del estándar de C ++.
Referencia:
Estándar C ++ 03:
15.4 Especificaciones de excepción [except.spec]
Si una función virtual tiene una especificación de excepción, todas las declaraciones, incluida la definición, de cualquier función que invalide esa función virtual en cualquier clase derivada solo permitirán excepciones permitidas por la especificación de excepción de la función virtual de clase base.
[Ejemplo:
struct B
{
virtual void f() throw (int, double);
virtual void g();
};
struct D: B
{
void f(); // ill-formed
void g() throw (int); // OK
};
La declaración de
D::f
está mal formada porque permite todas las excepciones, mientras queB::f
solo permiteint
ydouble
. ]