excepción c ++: throwing std :: string

Me gustaría lanzar una excepción cuando mis métodos C ++ encuentran algo raro y no se pueden recuperar. ¿Está bien lanzar un puntero std::string ?

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; } } 

Sí. 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 ellos mismos pueden lanzar una excepción durante el uso. Si eso sucede, ¿dónde estarás?

boost tiene un excelente documento con buen estilo para excepciones y manejo de errores. Vale la pena leerlo.

Algunos principios:

  1. tienes una clase base std :: exception, deberías tener tus excepciones derivadas de ella. De esa manera, el manejador de excepciones general aún tiene algo de información.

  2. No arroje punteros sino objete, de esa manera la memoria se maneja por usted.

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 úsala 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 "< 

Todo esto trabajo:

 #include  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ías preferir h a f a g. Tenga en cuenta que, en la opción menos preferible, debe liberar la memoria de forma explícita.

Funciona, pero no lo haría si fuera tú. Parece que no borras los datos del montón cuando terminas, lo que significa que has creado una pérdida de memoria. El comstackdor de C ++ se encarga de garantizar que los datos de excepción se mantengan con vida incluso cuando se extrae la stack, por lo tanto, no sienta que necesita usar el montón.

Por cierto, lanzar una std::string no es el mejor enfoque para empezar. Tendrá mucha más flexibilidad en el futuro si usa un objeto contenedor simple. Puede encapsular una string por ahora, pero tal vez en el futuro desee incluir otra información, como algunos datos que causaron la excepción o quizás un número de línea (muy común, eso). No desea cambiar todo el manejo de excepciones en cada lugar de su código base, así que tome el camino correcto ahora y no arroje objetos crudos.

Además de probablemente arrojar algo derivado de std :: exception, debe lanzar provisionales 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 "< 
  • Debes lanzar temporarios anónimos para que el comstackdor se ocupe de la vida útil del objeto de lo que sea que estés lanzando: si lanzas algo nuevo-ed fuera del montón, alguien más tiene que liberar el objeto.
  • Debería capturar referencias para evitar el corte de objetos

.

Consulte la "C + efectiva de la edición 3 de Meyer" para obtener más información o visite https://www.securecoding.cert.org/.../ERR02-A.+Throw+temporaries+anonymous+y+catch+by+reference

La forma más simple de lanzar una excepción en C ++:

 #include  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 capta la excepción lanzada, la excepción se contiene y el progtwig continuará. Si no captas la excepción, entonces el progtwig 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.

Aunque esta pregunta es bastante antigua y ya se ha respondido, solo quiero agregar una nota sobre cómo hacer un manejo de excepciones adecuado en C ++ 11 :

Use std::nested_exception y std::throw_with_nested

Usar estos, en mi opinión, conduce a un diseño de excepciones más limpio y hace innecesario crear una jerarquía de clases de excepción.

Tenga en cuenta que esto le permite obtener un seguimiento de sus 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 excepción adecuado que volverá a lanzar excepciones anidadas.

¡Ya que puede hacer esto con cualquier clase de excepción derivada, puede agregar mucha información a tal retroceso! También puede echar un vistazo a mi MWE en GitHub , donde una traza inversa 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"