Me gustaría lanzar una excepción cuando mis métodos de C ++ encuentran algo extraño y no se pueden recuperar. ¿Está bien lanzar un std::string
puntero?
Esto es lo que estaba deseando hacer:
void Foo::Bar() {
if(!QueryPerformanceTimer(&m_baz)) {
throw new std::string("it's the end of the world!");
}
}
void Foo::Caller() {
try {
this->Bar(); // should throw
}
catch(std::string *caught) { // not quite sure the syntax is OK here...
std::cout << "Got " << caught << std::endl;
}
}
Respuestas:
Si.
std::exception
es la clase de excepción base en la biblioteca estándar de C ++. Es posible que desee evitar el uso de cadenas como clases de excepción porque ellas mismas pueden lanzar una excepción durante el uso. Si eso sucede, ¿dónde estarás?boost tiene un excelente documento sobre buen estilo para excepciones y manejo de errores. Vale la pena leerlo.
fuente
Algunos principios:
tiene una clase base std :: exception, debe tener sus excepciones derivadas de ella. De esa manera, el manejador de excepciones general todavía tiene algo de información.
No arrojes punteros sino objeciones, de esa manera se maneja la memoria por ti.
Ejemplo:
struct MyException : public std::exception { std::string s; MyException(std::string ss) : s(ss) {} ~MyException() throw () {} // Updated const char* what() const throw() { return s.c_str(); } };
Y luego úsalo en tu código:
void Foo::Bar(){ if(!QueryPerformanceTimer(&m_baz)){ throw MyException("it's the end of the world!"); } } void Foo::Caller(){ try{ this->Bar();// should throw }catch(MyException& caught){ std::cout<<"Got "<<caught.what()<<std::endl; } }
fuente
Todos estos funcionan:
#include <iostream> using namespace std; //Good, because manual memory management isn't needed and this uses //less heap memory (or no heap memory) so this is safer if //used in a low memory situation void f() { throw string("foo"); } //Valid, but avoid manual memory management if there's no reason to use it void g() { throw new string("foo"); } //Best. Just a pointer to a string literal, so no allocation is needed, //saving on cleanup, and removing a chance for an allocation to fail. void h() { throw "foo"; } int main() { try { f(); } catch (string s) { cout << s << endl; } try { g(); } catch (string* s) { cout << *s << endl; delete s; } try { h(); } catch (const char* s) { cout << s << endl; } return 0; }
Debería preferir h af af g. Tenga en cuenta que, en la opción menos preferible, debe liberar la memoria de forma explícita.
fuente
const char
un error lanzar un puntero a una variable local? Sí, por supuesto, sé que el compilador colocará la cadena c en la sección no modificada que no cambiará la dirección hasta que se ejecute una aplicación. Pero no está definido; más aún, ¿qué sería si este código estuviera en una biblioteca que desapareció justo después de arrojar un error? Por cierto, yo también hice muchas cosas malas en mi proyecto, solo soy un estudiante. Pero debería haberlo pensado ...Funciona, pero no lo haría si fuera tú. No parece que esté eliminando esos datos del montón cuando haya terminado, lo que significa que ha creado una pérdida de memoria. El compilador de C ++ se encarga de garantizar que los datos de excepción se mantengan vivos incluso cuando se abre la pila, por lo que no sienta que necesita usar el montón.
Por cierto, lanzar un
std::string
no es el mejor enfoque para empezar. Tendrá mucha más flexibilidad en el futuro si usa un objeto contenedor simple. Es posible que solo encapsule unstring
por ahora, pero tal vez en el futuro desee incluir otra información, como algunos datos que causaron la excepción o tal vez un número de línea (muy común, eso). No desea cambiar todo el manejo de excepciones en cada lugar de su base de código, así que tome el camino correcto ahora y no arroje objetos crudos.fuente
Además de probablemente lanzar algo derivado de std :: exception, debería lanzar temporales anónimos y capturar por referencia:
void Foo::Bar(){ if(!QueryPerformanceTimer(&m_baz)){ throw std::string("it's the end of the world!"); } } void Foo:Caller(){ try{ this->Bar();// should throw }catch(std::string& caught){ // not quite sure the syntax is ok here... std::cout<<"Got "<<caught<<std::endl; } }
.
Consulte "Effective C ++ - 3rd edition" de Meyer para obtener más detalles o visite https://www.securecoding.cert.org/.../ERR02-A.+Throw+anonymous+temporaries+and+catch+by+reference
fuente
La forma más sencilla de lanzar una excepción en C ++:
#include <iostream> using namespace std; void purturb(){ throw "Cannot purturb at this time."; } int main() { try{ purturb(); } catch(const char* msg){ cout << "We caught a message: " << msg << endl; } cout << "done"; return 0; }
Esto imprime:
We caught a message: Cannot purturb at this time. done
Si detecta la excepción lanzada, la excepción está contenida y el programa continuará. Si no detecta la excepción, entonces el programa existe e imprime:
This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.
fuente
catch (std::exception&)
, no lo entenderé.Aunque esta pregunta es bastante antigua y ya ha sido respondida, solo quiero agregar una nota sobre cómo hacer un manejo adecuado de excepciones en C ++ 11 :
Utilice
std::nested_exception
ystd::throw_with_nested
El uso de estos, en mi opinión, conduce a un diseño de excepción más limpio y hace que sea innecesario crear una jerarquía de clases de excepción.
Tenga en cuenta que esto le permite obtener un seguimiento de las excepciones dentro de su código sin necesidad de un depurador o un registro engorroso. Se describe en StackOverflow aquí y aquí , cómo escribir un controlador de excepciones adecuado que volverá a generar excepciones anidadas.
Dado que puede hacer esto con cualquier clase de excepción derivada, ¡puede agregar mucha información a dicho rastreo! También puede echar un vistazo a mi MWE en GitHub , donde un backtrace se vería así:
Library API: Exception caught in function 'api_function' Backtrace: ~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed ~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
fuente