2010-08-31 7 views
5

Я использую механизм сценариев Qt в своем приложении как альтернативный способ доступа пользователя к его функциям. Таким образом, я экспортирую некоторые классы C++ в Qt ScriptEngine, который будет служить интерфейсом для приложения. Проблема в том, что эти классы C++ могут генерировать исключения.Обработка исключений C++, брошенных в функцию, экспортированных в QtScript

У меня есть класс ScriptInterface, запущенный в своем потоке, прислушиваясь к запросам на обработку скриптов. Поэтому, когда я оцениваю скрипт пользователя, у меня есть блок try/catch, который обрабатывает исключения, и печатает ошибку на консоли в приложении.

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

Это отлично работает в окнах ... но не работает в linux- программы завершается с этим сообщением:

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

Я догадывался, что это было из-за исключения ых до обработчик события (поскольку механизм сценария использует сигналы для вызова функций в моих экспортированных классах), поэтому я переопределял QApplication :: notify, чтобы обрабатывать исключения там, но они не были пойманы.

Мой вопрос: я делаю что-то принципиально неправильно? Кроме того, в качестве альтернативы можно ли явно передать исключения скриптов из моих классов C++?

Заранее спасибо

EDIT: исправили описание включить улов (...) заявление.

ОБНОВЛЕНИЕ (РЕШЕНИЕ): Я «исправил» эту проблему, следуя стратегии, аналогичной той, которая описана в принятом ответе. Хотя я не пришел к источнику того, почему исключения не попадают в 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(), и теперь у вас есть сообщение, трассировка и номер строки в скрипте, где произошла ошибка!

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

+0

Есть ли функция с [спецификациями исключения] (http://www.gotw.ca/publications/mill22.htm)? –

+0

Не где-нибудь в моих классах –

+0

Does catch (...) {} 'catch this exception? – tibur

ответ

3

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

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

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

+1

Супер поздно согласен, но я вернулся к этой проблеме на этой неделе и в основном сделал что-то очень похожее на то, что вы описали. Я отредактирую сообщение, чтобы показать свое решение для моего конкретного случая. Благодаря! –

1

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