3

Python でサブクラス化されることを意図した C++ オブジェクトを公開しています。構築されると、これらのオブジェクトは一部のコンテナー C++ 側によって参照されます。(実際には std::map) 1 つのオブジェクトは、このコンテナーから明示的に削除された後にのみ破棄できます。ただし、それらは Python によって管理されているため、Python への参照が残っていなくてもコンテナーによって参照されたままになると破棄されます。

オブジェクトを作成したときに、オブジェクトへの参照を保持していることを Python に伝える必要があります。それを行う簡単な方法が見つかりません。「返されたオブジェクトへの参照カウントを1つ増やす」ことを意味する呼び出しポリシーは見つかりませんでした。それを行うには、独自の呼び出しポリシーを実装する必要がありますか? (呼び出しポリシーを実装する方法がわかりません)または別の方法がありますか?

4

2 に答える 2

4

構築中のオブジェクトへの参照カウントを増やす特別なポリシーを書きました。

template <class Base = default_call_policies>
struct incref_return_value_policy : Base
{
    static PyObject *postcall(PyObject *args, PyObject *result)
    {
        PyObject *self = PyTuple_GET_ITEM(args, 0);
        Py_INCREF(self);
        return result;
    }
};

その後、他のポリシーとして使用できます。

class_<A>("A", init<>()[ incref_return_value_policy<>() ] );
于 2012-05-14T16:56:41.487 に答える
1

これが私があなたが望むと思うことをする小さな例です。手順全体は、Pythonで特定のタイプのインスタンスを構築するときに、Boost.Pythonに実際に別のクラスを使用するように指示し、カスタムのコンストラクターに最初の引数としてPythonオブジェクトを渡すように指示する「ホルダー」クラスの使用を中心にしています。ラッパークラス。あなたはここでより多くの情報を見つけることができます:

http://www.boost.org/doc/libs/1_48_0/libs/python/doc/v2/class.html

(特に「HeldTypeセマンティクス」の説明を参照してください)。

#include "boost/python.hpp"

namespace bp = boost::python;

class Base {
public:
    virtual double go(int x) const = 0;
    virtual ~Base() {}
};

class PyBase : public Base {
public:
    explicit PyBase(PyObject* self) : _self(self) {
        Py_INCREF(_self); // THIS LEAKS MEMORY IF THERE'S NO DECREF!
    }
    virtual double go(int x) const {
        return bp::call_method<double>(_self, "go", x);
    }
private:
    PyObject * _self;
};

BOOST_PYTHON_MODULE(example) {
    bp::class_<Base,PyBase,boost::noncopyable>(
        "Base",
        bp::init<>() // the PyObject* arg is implicit
    ) 
        .def("go", &PyBase::go)
        ;
}

ただし、いくつかの注意点があります。

  • goから継承するPythonで実装しないとBase、無限再帰に関する役に立たないPython例外メッセージが表示されます。また、デフォルトの実装がある場合に仮想関数をC ++にフォールバックする方法もわかりません(bp::wrapper非常によく似た処理を行うのコードを見ると、おそらく理解できます)。

  • 参照またはポインターによってC++関数からオブジェクトを返す場合、返されたインスタンスが実際に最初からPyBaseオブジェクトでない限り、Baseオブジェクトを含むPythonオブジェクトはありません(それについて考えると、PyBaseコース)。

  • 値で返す場合は、呼び出しからテンプレート引数をPyObject*削除する前に、最初の引数としてをとるコピーコンストラクターを追加する必要があります。boost::noncopyablebp::class_

  • コンストラクターのPy_INCREFステートメントは、「コード」がこのオブジェクトへの追加の参照を取得していることをPythonに通知します。しかし、対応するものをどのように追加するかは私にはわかりません。オブジェクトがすべてある場合、後でそれを取得する方法はありませPy_DECREFん。std::mapBase*PyObject*

  • 上記の問題を回避する1つの方法は、bp::handle<>またはのコンテナーをbp::object作成し、それらの1つを作成selfしてコンテナーに入れることです。ただし、その場合、静的デストラクタ時にPythonデストラクタが呼び出されるとセグメンテーション違反が発生するため、プログラムが終了する前にこれらのコンテナが空になっていることを確認する必要があります。

于 2012-05-14T02:03:32.223 に答える