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で例外がキャッチされない理由のソースには行っていませんが(現在、私の疑いは、Linuxでm_engine->evaluateが別のスレッドを生成することです)、意図した例外スローの方法を使い始めました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()、エラーが発生したスクリプトのメッセージ、トレース、および行番号が表示されます。

これが誰かを助けることを願っています!

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 に答える