私のプログラムでは、C++ で Python オブジェクトへの参照を管理しています。つまり、すべてのクラスは、対応する python オブジェクトへのポインターを含むクラス Referenced から派生しています。
class Referenced
{
public:
unsigned use_count() const
{
return selfptr->ob_refcnt;
}
void add_ref() const
{
Py_INCREF(selfptr);
}
void remove_ref() const
{
Py_DECREF(selfptr);
}
PyObject* selfptr;
};
Referenced から派生したオブジェクトを保持するために intrusive_ptr を使用します。これにより、必要な Python オブジェクトへの参照を C++ で簡単に保持し、必要に応じてそれらにアクセスできます。しかし、Python オブジェクトが C++ から削除されるとき、つまり、selfptr->ob_refcnt == 1 であるかどうかにかかわらず、Py_DECREF(selfptr) を呼び出すときに、私のプログラムが (Windows でのみ) クラッシュします。このアプローチは問題ありませんか?
Upd:私は最終的に自分のプログラムの問題を見つけました。オブジェクトの削除とは直接関係ありませんでした。最初の質問を確認するために、Python オブジェクトへの参照を記憶し、必要に応じて解放する単純な拡張モジュールを実装しました。はい、これ:
#include <Python.h>
static PyObject* myObj;
static PyObject* acquirePythonObject(PyObject* self, PyObject* obj)
{
printf("trying to acquire python object %p, refcount = %d\n", obj, obj->ob_refcnt);
myObj = obj;
Py_INCREF(myObj);
printf("reference acquired\n");
return Py_True;
}
static PyObject* freePythonObject(PyObject*, PyObject*)
{
printf("trying to free python object %p, refcount = %d\n", myObj, myObj->ob_refcnt);
Py_DECREF(myObj);
printf("reference removed\n");
return Py_True;
}
static PyMethodDef moduleMethods[] =
{
{"acquirePythonObject", acquirePythonObject, METH_O, "hold reference to python object."},
{"freePythonObject", freePythonObject, METH_NOARGS, "free reference to python object."},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initmodule(void)
{
Py_InitModule("module", moduleMethods);
}
そしてpythonスクリプト:
import module
class Foo:
def __init__(self):
print "Foo is created"
def __deinit__(self):
print "Foo is destroyed"
def acquireFoo():
foo = Foo()
module.acquirePythonObject(foo)
def freeFoo():
module.freePythonObject()
if __name__ == "__main__":
acquireFoo()
freeFoo()
サンプルは Windows と Linux でシームレスに実行されます。以下は出力です。
Foo is created
trying to acquire python object 0x7fa19fbefd40, refcount = 2
reference acquired
trying to free python object 0x7fa19fbefd40, refcount = 1
Foo is destoryed
reference removed