0

SWIG を使用して、Python で C++ クラスと C++ 関数をラップしました。

class Module { ... };
void register_module(Module *m);

関数 register_module() は、指定されたモジュールをグローバル リストに配置して、それ以降、C++ コードがモジュールのポインターを保持し、それを使用できるようにします。

ここで、組み込みの Python インタープリターから実行される次の Python コードがクラッシュします。

>>> register_module(Module())

一方、次の python コードはクラッシュしません

>>> m = Module()
>>> register_module(m)

明らかに、その理由は、最初のケースではオブジェクトが python によってガベージ コレクションされるのに対し、2 番目のケースではそうではないためです。

最初のケースで作成され、C++ コードで使用される匿名オブジェクトを Python が削除しないようにする最善の方法は何ですか?

register_module() 関数で、関連する python プロキシ オブジェクトを保持し、その参照カウントを増やす方法はありますか?

(問題のクラスが Swig::Director クラスにクロスキャストできる場合、これが可能であることはわかっていますが、これは Python で定義された Module サブクラスのインスタンスがあることを前提としていますが、ここでは当てはまりません) .

4

1 に答える 1

1

解決。
ステップ 1 : Module クラスにメンバーを追加し、2 つのメソッドを追加します。

class Module {
public:
    PyObject *obj;
    void incref() { Py_INCREF(obj); }
    void decref() { Py_DECREF(obj); }
    ...
};

ステップ 2 : register_module() で参照カウントを増やします。

void register_module(Module *m) {
    m->incref();
    ...
}

(どこかで減らすことを忘れないでください)

ステップ 3 : SWIG で生成されたラッパーをハックして、Module オブジェクトが Python から構築されるたびに obj メンバーを PyObject ラッパーに設定します。

SWIG で生成されたファイル ModulePYTHON_wrap.cxx で、次の場所を見つけます。

SWIGINTERN PyObject *_wrap_new_Module(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
  PyObject *resultobj = 0;
  ...
  Module *result = 0 ;
  ...
  if ( arg1 != Py_None ) {
    /* subclassed */
    result = (Module *)new SwigDirector_Module(arg1);
  } else {
    result = (Module *)new Module();
  }

  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Module, SWIG_POINTER_NEW |  0 );
  return resultobj;
  ...
}

取得result->obj =する前に挿入:resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Module, SWIG_POINTER_NEW | 0 );

  result->obj = resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Module, SWIG_POINTER_NEW |  0 );

ステップ 4 : 生成されたラッパーに修正を自動的に実装するように SWIG に指示します。

インターフェイス ファイルに次の typemap 宣言を追加します。

%typemap(out) Module* {
   result->obj = $result = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Module, SWIG_POINTER_NEW |  0 );
}

これは、新しい Module オブジェクトをラップするためにデフォルトで生成されるコードを効果的にオーバーライドします。

于 2013-03-26T00:11:49.793 に答える