2012-04-09 33 views
12
try 
{ // `count()` throws exception 
    connect(thread, SIGNAL(started()), engine, SLOT(count())); 
} 
catch(const X& e) 
{} 

A partir de Qt-5, consigo el error siguiente:¿Cómo atrapar excepciones en Qt?

Qt has caught an exception thrown from an event handler. Throwing exceptions from an event handler is not supported in Qt. You must not let any exception whatsoever propagate through Qt code. If that is not possible, in Qt 5 you must at least re-implement QCoreApplication::notify() and catch all exceptions there.

Si no puedo detectar las excepciones en forma convencional como se indica arriba, a continuación, donde se supone que debemos coger esos?

+0

tal vez debería poner el bloque try-catch en la función count(). .. – Kobe

+0

#vBx count throws – smallB

+1

Entonces su solución provista en la pregunta es buena – Kobe

Respuesta

8

where am I supposed to catch it?

Esto es exactamente por qué Qt no admite excepciones que lanzan a través de conexiones de señal/ranura. Si lo intenta, verá este mensaje:

Qt has caught an exception thrown from an event handler. Throwing exceptions from an event handler is not supported in Qt. You must reimplement QApplication::notify() and catch all exceptions there.

Como se menciona, es posible subclase QApplication y coger su excepción, pero que va a ser una forma muy molesto de manejar las cosas.

Si es posible, recomendaría reescribir el conteo de modo que no arroje.


¿Qué pasa si no se puede reescribir count()?

Por ejemplo, ¿qué ocurre si count() es parte de una función en una biblioteca de terceros que está utilizando?

No hay espacio en ninguna biblioteca oficial de Qt, así que si está utilizando una biblioteca de terceros con una ranura que arroja, probablemente sea una señal de que no es una buena biblioteca. Si desea utilizarlo de todos modos, le recomiendo que en lugar de detectarlo en QApplication::notify, cree un adaptador.

¿Qué significa eso? Primero crea un objeto que capture tu objeto incompleto de terceros en el constructor. En él, escriba una ranura que envuelva una llamada a la ranura de lanzamiento con un bloque try/catch. Ahora, en lugar de conectarse a la ranura del objeto incompleto de terceros, conéctese a la ranura de su nuevo objeto creado.

Hacer la excepción de esta manera mantiene el código relacionado junto y evita que QApplication::notify se llene con un grupo de bloques try/catch no relacionados si encuentra más de una de estas funciones problemáticas.

Por ejemplo:

class BadCounter { 
Q_OBJECT 
public slots: 
    void count() { throw CounterError("unable to count"); } 
}; 

class CounterAdaptor { 
Q_OBJECT 
    BadCounter* counter_; 
public: 
    CounterAdaptor(BadCounter* counter) { 
    counter_ = counter; 
    } 
public slots: 
    void count() { 
    try { 
     counter_->count(); 
    } catch (const CounterError& e) { 
     std::cerr << e.what() << std::endl; 
    } 
    } 
}; 

int main() { 
    BadCounter engine; 
    CounterAdaptor adaptor(&engine); 
    QThread* thread = new QThread(); 
    connect(thread,SIGNAL(started()),&adaptor,SLOT(count())); 
    thread.start(); 
    ... // etc... 
    delete thread; 
} 

Qué pasa si usted quiere manejar algo que podría ser lanzado desde cualquier lugar?

El ejemplo obvio de este tipo de preocupación global es una excepción inesperada. Los errores pueden ocurrir en cualquier lugar. Sería deseable registrar tantos detalles sobre el evento como sea posible para que la causa pueda ser identificada y corregida. En este caso, sería desea volver a implementar QApplication::notify en su propia subclase como se muestra en jichi's answer. Usar un controlador global para preocupaciones globales es bastante razonable.

+0

sí, creo que tendré que volver a escribir esto y no tirar. Gracias. – smallB

+0

Es completamente posible llamar a 'count()', guardar el resultado, y luego pasar el resultado a 'SLOT' si' SLOT' no permite lanzar una excepción. –

+0

SLOT no toma el resultado de conteo(). Esta es la macro SLOT: '# define SLOT (a)" 1 "# a' – cgmb

-8

Usted puede probar esto para un ejemplo, al ver que su solución es buena:

int f() 
{ 
    throw 1; 
    return 5; 
} 

void g(int x) 
{ 
    cout << x << endl; 
} 

int main() 
{ 
    try { 
      g(f()); 
    }catch(int) 
    { 
     cout << "Caught exception" << endl; 
    } 
} 
+0

#vBx usted no usa ninguna conexión de señales/slots, ¿me falta algo? – smallB

+0

@smallB: las señales y las ranuras son construcciones específicas de QT, lo que vBx le brinda aquí es la solución estándar de C++. –

+0

@Als lo veo pero mi pregunta es específica de qt. Pensé que la noción de ranura de señal sería un buen regalo. Además, si tuviera en cuenta que no pregunto cómo usar try catch block. – smallB

6

Si alguien necesita un código de ejemplo para anular QApplication :: Notify, tengo uno de aquí (en japonés): http://www.02.246.ne.jp/~torutk/cxx/qt/QtMemo.html

#include "MyApplication.h" 
#include <exception> 

MyApplication::MyApplication(int& argc, char** argv) : 
    QApplication(argc, argv) {} 

bool MyApplication::notify(QObject* receiver, QEvent* event) { 
    bool done = true; 
    try { 
    done = QApplication::notify(receiver, event); 
    } catch (const std::exception& ex) { 
    // ログや何らかの回復処理 
    } catch (...) { 
    // ログや何らかの回復処理 
    } 
    return done; 
} 
+0

¿Qué es MyApplication? ¿Es eso un diálogo? – Petr

+1

clase MyApplication: public QApplication – jichi

+0

funciona, gracias – Petr

Cuestiones relacionadas