2010-08-31 15 views
5

Estoy usando el motor de script Qt en mi aplicación como una forma alternativa para que el usuario acceda a su funcionalidad. Como tal, exporto algunas clases de C++ al Qt ScriptEngine, que servirá como interfaz para la aplicación. El problema es que estas clases de C++ pueden arrojar excepciones.Manejo de la excepción C++ lanzada en la función exportada a QtScript

Tengo una clase "ScriptInterface" ejecutándose en su propio hilo, escuchando solicitudes para procesar scripts. Entonces cuando evalúo la secuencia de comandos de un usuario, tengo un bloque try/catch alrededor para manejar las excepciones e imprimir el error en la consola de la aplicación.

... 
try { 
    m_engine->evaluate(script, name); 
} 
catch (Exception const& e) { 
    // deal with it 
} 
catch (...) { 
    // scary message 
} 

Esto funciona perfectamente en Windows ... pero no funciona en linux el programa termina con este mensaje:

terminate called after throwing an instance of 'Basilisk::InvalidArgumentException' 
    what(): N8Basilisk24InvalidArgumentExceptionE 
Aborted 

tuve el presentimiento de que era debido a las excepciones burbujear hasta el controlador de eventos (dado que el motor de scripts usa señales para llamar a las funciones en mis clases exportadas), así que reimplementé QApplication :: notify, para manejar excepciones allí, pero no fueron atrapadas.

Mi pregunta es, ¿estoy haciendo algo fundamentalmente malo? Además, como alternativa, ¿es posible lanzar explícitamente excepciones de guiones dentro de mis clases de C++?

Gracias de antemano

EDIT: fijan la descripción para incluir el (...) sentencia catch.

ACTUALIZACIÓN (SOLUCIÓN): "solucioné" este problema siguiendo una estrategia similar a la que se describe en la respuesta aceptada. Aunque no he ido a la fuente de por qué las excepciones no quedan atrapadas en Linux (sospecho ahora, es que m_engine-> evalúan generar un hilo separado en Linux), pero he comenzado a usar el previsto manera de excepción lanzando en Qt Scripts, y eso es QScriptContext::throwError().

En los casos en que mi función sería el siguiente: (ejemplo al azar)

void SomeClass::doStuff(unsigned int argument) { 
    if (argument != 42) { 
     throw InvalidArgumentException(
      "Not the answer to Life, the Universe and Everything."); 
    } 

    // function that is not part of the scripting environment, 
    // and can throw a C++ exception 
    dangerousFunction(argument); 
} 

ahora es la siguiente: (prestar especial atención al tipo de retorno)

QScriptValue SomeClass::doStuff(unsigned int argument) { 
    if (argument != 42) { 
     // assuming m_engine points to an instance of 
     // QScriptEngine that will be calling this function 
     return m_engine->currentContext()->throwError(QScriptContext::SyntaxError, 
      "Not the answer to Life, the Universe and Everything."); 
    } 


    try { 
     // function that is not part of the scripting environment, 
     // and can throw a C++ exception 
     dangerousFunction(argument); 
    } catch (ExpectedException const& e) { 
     return m_engine->currentContext()->throwError(QScriptContext::UnknownError, 
      e.message()); 
    } 

    // if no errors returned, return an invalid QScriptValue, 
    // equivalent to void 
    return QScriptValue(); 
} 

Entonces, ¿dónde puede uno lidiar con estos errores de script? Después de la llamada al QScriptEngine::evaluate() puede verificar si hay excepciones no detectadas, con QScriptEngine::hasUncaughtException(), obtenga el objeto de error con uncaughtException(), ¡y ahora tiene el mensaje, el rastreo y el número de línea en el script donde ocurrió el error!

Espero que esto ayude a alguien!

+0

¿Hay alguna función con [especificaciones de excepción] (http://www.gotw.ca/publications/mill22.htm) involucrado? –

+0

No en ninguna parte de mis clases –

+0

¿'catch (...) {}' atrapa esa excepción? – tibur

Respuesta

3

Me encontré con un tipo similar de problema al tratar de usar SWIG con Python para envolver las bibliotecas de C++. Eventualmente, lo que sucedió fue que hice un resguardo para todas las clases envueltas que captaron la excepción y fallaron silenciosamente. Afortunadamente, tuve el lujo de envolver la funcionalidad que solo pasaba clases de contenedor y objetos de patrón de estado, por lo que podía verificar fácilmente si algo andaba mal. ¿Puedo sugerir lo mismo para ti?

  1. Envuelva las funciones que desee con otra función, la misma interfaz excepto el valor de retorno.
  2. Cree un objeto que contenga no solo el tipo de devolución solicitada sino también un indicador de error.
  3. Haga que el script se asegure de verificar las excepciones.

Y sí, es muy posible que un motor de secuencia de comandos para lanzar excepciones de C++ si se ha dado acceso a una fábrica de excepción (una clase cuyo único propósito es arrojar excepciones de C++.)

+1

Súper tarde acepte, pero volví a este problema esta semana y básicamente hice algo muy similar a lo que describió. Editaré mi publicación para mostrar mi solución para mi caso específico. ¡Gracias! –

1

Ejecute su programa bajo un depurador y coloque un punto de interrupción dentro de la función terminate() de la biblioteca en tiempo de ejecución. De esa forma, se detendrá en terminate() en el depurador y, al inspeccionar la pila de llamadas, verá desde donde se llamó a terminate().

Cuestiones relacionadas