10

私のプログラムでは、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
4

1 に答える 1

1

このアプローチは大丈夫ですか?

基本的にですが...

  • add_ref/remove_refが正しい回数呼び出されるという保証はありません(RAII を使用するとこれが自動化されます - おそらくそれがあなたの intrusive_ptr の機能ですか?)
  • 度も試してみると、remove_refPython が何を保証するのかわかりません。selfptr = NULLrefcount が 1 -> 0 になることがわかっているときに 設定すると、これをキャッチできます
    • ハードにクラッシュするか、明示的にチェックするか、またはPy_XDECREF
    • さらに良いことに、Py_CLEAR代わりに使用してください

そして最後に...クラッシュダンプまたは診断情報はありますか?

于 2013-01-16T16:10:32.620 に答える