Я использую механизм сценариев Qt в своем приложении в качестве альтернативного способа доступа пользователя к его функциям. Поэтому я экспортирую некоторые классы C ++ в Qt ScriptEngine, который будет служить интерфейсом для приложения. Проблема в том, что эти классы C ++ могут генерировать исключения.
У меня есть класс "ScriptInterface", работающий в своем собственном потоке, который прослушивает запросы на обработку сценариев. Поэтому, когда я оцениваю сценарий пользователя, у меня есть блок try / catch для обработки исключений и вывод ошибки на консоль в приложении.
...
try {
m_engine->evaluate(script, name);
}
catch (Exception const& e) {
// deal with it
}
catch (...) {
// scary message
}
Это прекрасно работает в Windows ... но не работает в Linux - программа завершается с этим сообщением:
terminate called after throwing an instance of 'Basilisk::InvalidArgumentException'
what(): N8Basilisk24InvalidArgumentExceptionE
Aborted
Я догадывался, что это произошло из-за того, что исключения были обработаны обработчиком событий (поскольку обработчик сценариев использует сигналы для вызова функций в моих экспортированных классах), поэтому я переопределил QApplication :: notify, чтобы обработать там исключения они не были пойманы.
У меня вопрос: я делаю что-то в корне неправильно? Также, в качестве альтернативы, можно ли явно генерировать исключения сценариев из моих классов C ++?
Заранее спасибо
РЕДАКТИРОВАТЬ: исправлено описание, чтобы включить оператор catch (...).
ОБНОВЛЕНИЕ (РЕШЕНИЕ): Я "исправил" эту проблему, следуя стратегии, аналогичной изложенной в принятом ответе. Хотя я не дошел до источника, почему исключения не попадают в linux (теперь я подозреваю, что m_engine-> оценивает порождение отдельного потока в linux), но я начал использовать предназначенный способ выдачи исключений в Qt Scripts, и это QScriptContext::throwError()
.
В тех случаях, когда моя функция будет выглядеть так: (случайный пример)
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);
}
Теперь это так: (обратите особое внимание на тип возвращаемого значения)
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();
}
Так, где каждый имеет дело с этими ошибками сценария? После вызова QScriptEngine::evaluate()
вы можете проверить наличие необработанных исключений с помощью QScriptEngine::hasUncaughtException()
, получить объект ошибки с помощью uncaughtException()
, и теперь у вас есть сообщение, трассировка и номер строки в скрипте, где произошла ошибка!
Надеюсь, это кому-нибудь поможет!