5

我在我的应用程序中使用 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->evaluate 在 linux 上生成一个单独的线程),但我已经开始使用预期的异常抛出方式在 Qt 脚本中,即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(),现在脚本中出现错误的消息、trace、行号就知道了!

希望这可以帮助某人!

4

2 回答 2

3

在尝试将 SWIG 与 Python 一起使用来包装 C++ 库时,我遇到了类似类型的问题。最终发生的事情是,我为所有捕获异常并悄悄失败的包装类创建了一个存根。幸运的是,我拥有仅传递容器类和状态模式对象的包装功能,因此我可以轻松检查是否有问题。我可以给你同样的建议吗?

  1. 用另一个函数包装你想要的函数,除了返回值外,相同的接口。
  2. 创建一个对象,该对象不仅包含请求的返回类型,还包含错误指示符。
  3. 让脚本确保检查异常。

是的,如果您授予脚本引擎访问异常工厂(一个唯一目的是抛出 C++ 异常的类)的访问权限,那么脚本引擎很有可能抛出 C++ 异常。

于 2010-09-03T13:26:25.107 回答
1

在调试器下运行程序并在运行时库的 terminate() 函数中放置一个断点。这样,您将在调试器中的 terminate() 处停止,然后通过检查调用堆栈,您将看到调用 terminate() 的位置。

于 2010-09-03T13:20:31.907 回答