Обработка исключения C ++, брошенного в функцию, экспортированную в QtScript - PullRequest
5 голосов
/ 31 августа 2010

Я использую механизм сценариев 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(), и теперь у вас есть сообщение, трассировка и номер строки в скрипте, где произошла ошибка!

Надеюсь, это кому-нибудь поможет!

Ответы [ 2 ]

3 голосов
/ 03 сентября 2010

Я столкнулся с подобным типом проблемы при попытке использовать SWIG с Python для упаковки библиотек C ++. В конце концов случилось то, что я сделал заглушку для всех упакованных классов, которые поймали исключение и потерпели неудачу. К счастью, у меня была такая роскошь, как функциональность упаковки, которая передавала только классы контейнеров и объекты шаблонов состояний, поэтому я легко могла проверить, что-то не так. Могу я предложить то же самое для вас?

  1. Оберните нужные функции другой функцией, с тем же интерфейсом, кроме возвращаемого значения.
  2. Создайте объект, который содержит не только запрошенный тип возвращаемого значения, но и индикатор ошибки.
  3. Пусть скрипт проверит наличие исключений.

И да, движок сценариев может создавать исключения C ++, если вы предоставили ему доступ к фабрике исключений (классу, единственная цель которого - генерировать исключения C ++.)

1 голос
/ 03 сентября 2010

Запустите вашу программу под отладчиком и поместите точку останова в функцию terminate () вашей библиотеки времени выполнения.Таким образом вы остановитесь на terminate () в отладчике, и, проверив стек вызовов, вы увидите, откуда был вызван terminate ().

...