Cómo lanzar una excepción de C++

Resuelto Terry Li asked hace 13 años • 5 respuestas

Tengo muy pocos conocimientos sobre el manejo de excepciones (es decir, cómo personalizar las declaraciones throw, try, catch para mis propios fines).

Por ejemplo, he definido una función de la siguiente manera:int compare(int a, int b){...}

Me gustaría que la función arroje una excepción con algún mensaje cuando aob sea negativo.

¿Cómo debo abordar esto en la definición de la función?

Terry Li avatar Dec 13 '11 03:12 Terry Li
Aceptado

Simple:

#include <stdexcept>

int compare( int a, int b ) {
    if ( a < 0 || b < 0 ) {
        throw std::invalid_argument( "received negative value" );
    }
}

La biblioteca estándar viene con una buena colección de objetos de excepción integrados que puedes lanzar. Tenga en cuenta que siempre debe lanzar por valor y capturar por referencia:

try {
    compare( -1, 3 );
}
catch( const std::invalid_argument& e ) {
    // do stuff with exception... 
}

Puede tener varias declaraciones catch() después de cada intento, por lo que puede manejar diferentes tipos de excepción por separado si lo desea.

También puedes volver a lanzar excepciones:

catch( const std::invalid_argument& e ) {
    // do something

    // let someone higher up the call stack handle it if they want
    throw;
}

Y para detectar excepciones independientemente del tipo:

catch( ... ) { };
nsanders avatar Dec 12 '2011 20:12 nsanders

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

uso std::nested_exceptionystd::throw_with_nested

En StackOverflow aquí y aquí se describe cómo puede obtener un seguimiento de sus excepciones dentro de su código sin necesidad de un depurador o un registro engorroso, simplemente escribiendo 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 seguimiento! También puedes echar un vistazo a mi MWE en GitHub , donde un seguimiento 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"
GPMueller avatar Oct 26 '2017 08:10 GPMueller

Simplemente agregue throwdonde sea necesario y trybloquee a la persona que llama que maneja el error. Por convención, solo debes descartar elementos que deriven de std::exception, así que inclúyelo <stdexcept>primero.

int compare(int a, int b) {
    if (a < 0 || b < 0) {
        throw std::invalid_argument("a or b negative");
    }
}

void foo() {
    try {
        compare(-1, 0);
    } catch (const std::invalid_argument& e) {
        // ...
    }
}

Además, consulte Boost.Exception .

Cat Plus Plus avatar Dec 12 '2011 20:12 Cat Plus Plus

Podrías definir un mensaje para lanzar cuando ocurre un determinado error:

throw std::invalid_argument( "received negative value" );

o podrías definirlo así:

std::runtime_error greatScott("Great Scott!");          
double getEnergySync(int year) {                        
    if (year == 1955 || year == 1885) throw greatScott; 
    return 1.21e9;                                      
}                                                       

Normalmente, tendrías un try ... catchbloque como este:

try {
// do something that causes an exception
}catch (std::exception& e){ std::cerr << "exception: " << e.what() << std::endl; }
serup avatar Feb 02 '2017 14:02 serup

Agregando a esta respuesta, ya que no parece ventajoso crear otra respuesta para estas preguntas y respuestas en este momento.

En el caso de que cree su propia excepción personalizada, que se deriva de std::exception, cuando detecte "todos los tipos de excepciones posibles", siempre debe comenzar las catchcláusulas con el tipo de excepción "más derivado" que pueda detectarse. Vea el ejemplo (de lo que NO hacer):

#include <iostream>
#include <string>

using namespace std;

class MyException : public exception
{
public:
    MyException(const string& msg) : m_msg(msg)
    {
        cout << "MyException::MyException - set m_msg to:" << m_msg << endl;
    }

   ~MyException()
   {
        cout << "MyException::~MyException" << endl;
   }

   virtual const char* what() const throw () 
   {
        cout << "MyException::what" << endl;
        return m_msg.c_str();
   }

   const string m_msg;
};

void throwDerivedException()
{
    cout << "throwDerivedException - thrown a derived exception" << endl;
    string execptionMessage("MyException thrown");
    throw (MyException(execptionMessage));
}

void illustrateDerivedExceptionCatch()
{
    cout << "illustrateDerivedExceptionsCatch - start" << endl;
    try 
    {
        throwDerivedException();
    }
    catch (const exception& e)
    {
        cout << "illustrateDerivedExceptionsCatch - caught an std::exception, e.what:" << e.what() << endl;
        // some additional code due to the fact that std::exception was thrown...
    }
    catch(const MyException& e)
    {
        cout << "illustrateDerivedExceptionsCatch - caught an MyException, e.what::" << e.what() << endl;
        // some additional code due to the fact that MyException was thrown...
    }

    cout << "illustrateDerivedExceptionsCatch - end" << endl;
}

int main(int argc, char** argv)
{
    cout << "main - start" << endl;
    illustrateDerivedExceptionCatch();
    cout << "main - end" << endl;
    return 0;
}

NOTA:

  1. El orden correcto debe ser al revés, es decir, primero usted, catch (const MyException& e)seguido de catch (const std::exception& e).

  2. Como puede ver, cuando ejecuta el programa tal como está, se ejecutará la primera cláusula catch (que probablemente sea lo que NO deseaba en primer lugar).

  3. Aunque el tipo capturado en la primera cláusula catch es de tipo std::exception, what()se llamará a la versión "adecuada" de - porque está capturado por referencia (cambie al menos el std::exceptiontipo de argumento capturado para que sea por valor - y experimentará el "objeto"). fenómenos de "slicing" en acción).

  4. En caso de que "algo de código debido al hecho de que se lanzó la excepción XXX..." haga cosas importantes CON RESPECTO al tipo de excepción, hay un mal comportamiento de su código aquí.

  5. Esto también es relevante si los objetos capturados fueran objetos "normales" como: class Base{};y class Derived : public Base {}...

  6. g++ 7.3.0en Ubuntu 18.04.1 genera una advertencia que indica el problema mencionado:

En la función 'void IllustratorDerivedExceptionCatch()': item12Linux.cpp:48:2: advertencia: se detectará la excepción de tipo 'MyException' catch(const MyException& e) ^~~~~

item12Linux.cpp:43:2: advertencia: por el controlador anterior para la captura 'std::exception' (excepción constante y e) ^~~~~

Nuevamente , diré que esta respuesta es solo para AGREGAR a las otras respuestas descritas aquí (pensé que vale la pena mencionar este punto, pero no pude describirlo en un comentario).

Guy Avraham avatar Sep 19 '2018 09:09 Guy Avraham