2011-07-20 14 views
15

Tengo una pregunta tonta. He leído este artículo sobre std :: excepción http://www.cplusplus.com/doc/tutorial/exceptions/catching std :: exception by reference?

En catch (exception& e), que dice:

Hemos colocado un controlador que atrapa los objetos de excepción por referencia (nótese el signo & después del tipo), por lo que este llama también clases derivadas de la excepción, como nuestro myex objeto de clase myexception.

¿Esto significa que al usar "&" también puede detectar la excepción de la clase principal? Pensé que & está predefinido en std :: exception porque es mejor pasar e (std :: exception) como referencia que el objeto.

+0

No entiendo su último párrafo. Pasar por referencia no tiene nada que ver con las excepciones y es fundamental en C++ para permitir el polimorfismo en tiempo de ejecución. –

+1

La respuesta es no: los objetos que puede capturar deben derivarse del tipo de excepción que está capturando, como mencionó en su publicación. Esto exhibe la relación IS-A. No puede atrapar una clase para padres si solo especifica niños en las cláusulas catch. – Chris

Respuesta

47

La razón para usar & con excepciones no es tanto el polimorfismo como evitar slicing. Si no fuera a usar &, C++ intentaría copiar la excepción lanzada en un std::exception recién creado, con la posibilidad de perder información en el proceso.Ejemplo:

#include <stdexcept> 
#include <iostream> 

class my_exception : public std::exception { 
    virtual const char *what() const throw() { 
    return "Hello, world!"; 
    } 
}; 

int main() { 
    try { 
    throw my_exception(); 
    } catch (std::exception e) { 
    std::cout << e.what() << std::endl; 
    } 
    return 0; 
} 

Esto imprimirá el mensaje por defecto para std::exception (en mi caso, St9exception) en lugar de Hello, world!, debido a que el objeto de excepción original se perdió por corte. Si cambiamos eso a un &:

#include <stdexcept> 
#include <iostream> 

class my_exception : public std::exception { 
    virtual const char *what() const throw() { 
    return "Hello, world!"; 
    } 
}; 

int main() { 
    try { 
    throw my_exception(); 
    } catch (std::exception &e) { 
    std::cout << e.what() << std::endl; 
    } 
    return 0; 
} 

Ahora sí vemos Hello, world!.

+3

+1; Guau, tu ejemplo y respuesta se parecen mucho a los míos. ¿Estás sentado detrás de mí? ;) –

+0

@Merlyn, no, creo que es la forma más sencilla de demostrar el problema :) – bdonlan

+1

+ bdonlan no entiendo que 'virtual const char * what() const throw() {' two functions? what() & throw() puede explicar esta sintaxis para la función. No he visto eso antes. – AbhimanyuAryan

0

El uso de la referencia a la excepción aquí puede reducir los objetos temporales creados, y también puede mantener el polimorfismo.

2

No, el & no tiene absolutamente ninguna relación con la naturaleza polimórfica de los manejadores de excepciones. Su redacción es muy pobre, parece indicar que el & es de alguna manera responsable. Este no es el caso. Estás en lo cierto, & simplemente pasa por referencia, que es un poco más eficiente.

También como regla general, you should really try to avoid cplusplus.com .

Actualización del enlace:What's wrong with cplusplus.com

+0

Cortar es mucho más importante que la eficiencia ... – bdonlan

+0

¿el enlace está reventado? – sje397

+0

@ sje397 hmm, parece que eliminaron el artículo, he actualizado el enlace. –

7

¿Esto significa que mediante el uso de "&" se puede también coger excepción de la clase padre?

No, esto no aumenta el alcance de donde detectará excepciones (por ejemplo, de la clase principal de la clase que contiene el código try/catch).

También no aumenta los tipos de excepciones que pueden ser capturadas, en comparación con la captura por valor (catch(std::exception e) sin la & - que todavía va a coger cada excepción que, o bien es std::exception o se deriva de ella).

Lo que aumenta es la cantidad de datos que obtendrá realmente cuando capture la excepción.

Si se lanza una excepción que deriva de std::exception, y la capta por su valor, entonces está descartando cualquier comportamiento adicional en esa clase de excepción. Se rompe polymorphism en la clase de excepción, debido a Slicing.

Un ejemplo:

class MyException : public std::exception 
{ 
public: 
    virtual const char* what() const 
    { 
     return "hello, from my exception!"; 
    } 
}; 

// ... 

try 
{ 
    throw MyException(); 
} 
catch(std::exception& e) 
{ 
    // This will print "hello, from my exception!" 
    std::cout << e.what() << "\n"; 
} 

// ... 

try 
{ 
    throw MyException(); 
} 
catch(std::exception e) 
{ 
    // This will print "Unknown exception" 
    std::cout << e.what() << "\n"; 
}