Swig исключение в классе директоров Python - PullRequest
1 голос
/ 03 апреля 2019

Я обертываю некоторые классы, используя директоры Swig в Python.Каждый из моих методов класса возвращает класс MyError.Что происходит, когда я получаю класс python из одного из моих C ++, и я забываю вернуть объект MyError (), но я не возвращаю ничего из «pass», или я забываю что-либо возвращать, мое программное обеспечение вылетает в конструкторе по умолчанию MyErrorкласс с нарушением прав чтения, и я не могу отследить это исключение с помощью блока try / catch.

Как в Swig правильно обрабатывать подобные ситуации?

Спасибо!

1 Ответ

2 голосов
/ 03 апреля 2019

Раздел 36.5.4 Развертывание исключений в документации SWIG:

Поскольку директора направляют вызовы методов в Python и прокси-серверы направляют их в C ++, обработка исключений являетсяважное беспокойствоПо умолчанию директора игнорируют исключения, возникающие во время вызовов методов, которые разрешаются в Python.Чтобы правильно обрабатывать такие исключения, необходимо временно перевести их в исключения C ++.Это можно сделать с помощью директивы% feature ("Director: Кроме").В большинстве случаев будет достаточно следующего кода:

%feature("director:except") {
    if ($error != NULL) {
        throw Swig::DirectorMethodException();
    }
}

Этот код будет проверять состояние ошибки Python после каждого вызова метода из директора в Python и генерировать исключение C ++ в случае ошибкипроизошло.Это исключение может быть перехвачено в C ++ для реализации обработчика ошибок.В настоящее время никакая информация об ошибке Python не сохраняется в объекте Swig :: DirectorMethodException, но это, вероятно, изменится в будущем.

Может случиться, что вызов метода происходит в Python, до C ++ проходит черезпрокси-класс, а затем обратно в Python через метод Director.Если в этот момент в Python возникает исключение, было бы хорошо, если бы это исключение вернулось к исходному вызывающему.Это можно сделать путем объединения обычной директивы% исключений с директором: кроме обработчика, показанного вышеВот пример подходящего обработчика исключений:

%exception {
    try { $action }
    catch (Swig::DirectorException &e) { SWIG_fail; }
}

Класс Swig :: DirectorException, используемый в этом примере, на самом деле является базовым классом Swig :: DirectorMethodException, поэтому он будет перехватыватьэто исключение.Поскольку состояние ошибки Python по-прежнему устанавливается при возникновении исключения Swig :: DirectorMethodException, Python зарегистрирует исключение, как только вернется функция оболочки C.

Пример

Вот пример test.i, который иллюстрирует эту технику:

%module test

%module(directors="1") test
%feature("director");

%feature("director:except") {
    if ($error != NULL) {
        throw Swig::DirectorMethodException();
    }
}

%exception {
    try { $action }
    catch (Swig::DirectorException &e) { SWIG_fail; }
}

%inline %{
    class MyError {
        int m_n;
    public:
        MyError(int n = 0) : m_n(n) {}
        ~MyError() {}
        int get() const { return m_n; }
    };

    class Demo {
    public:
        Demo() {}
        virtual ~Demo() {}
        virtual MyError test() { return MyError(5); }
    };

    int func(Demo* d) { return d->test().get(); }
%}

После сборки и компиляции демонстрационная версия:

>>> import test
>>> d=test.Demo()  # default class implementation
>>> test.func(d)   # Call virtual method in a C++ test function.
5

Вышеописанное работало нормально.Ниже корректно переопределяется:

>>> class Demo2(test.Demo):  # New class
...  def test(self):         # Override virtual function
...   return 7               # But don't return a MyError object.
...
>>> d=Demo2()
>>> test.func(d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: SWIG director type mismatch in output value of type 'MyError'

Это перехватило исключение и вернуло полезное исключение.Ниже корректно переопределяет:

>>> class Demo2(test.Demo):
...  def test(self):
...   return test.MyError(7)
...
>>> d=Demo2()
>>> test.func(d)
7
...