[C++-sig] pybindgen: allow_subclassing option causing reference parameters to be copied?
Gustavo Carneiro
gjcarneiro at gmail.com
Tue Jun 30 15:29:39 CEST 2009
2009/6/29 J. Michael Owen <mikeowen at llnl.gov>
> Hi Gustavo,
> Hmm. I tried this example, but the generated code seems to be still trying
> to generate a copy. Here's the example source I'm trying expose:
>
> #include <iostream>
>
> class A {
> public:
> A(const int val): mVal(val) {}
> private:
> int mVal;
> A();
> A(const A& rhs);
> A& operator=(const A& rhs);
> };
>
> class B {
> public:
> B() {}
> virtual ~B() {}
> virtual void some_virtual_method(const A& a) const { std::cerr << &a <<
> std::endl; }
> private:
> };
>
> I try to expose these objects with the following pybindgen code:
>
> mod = Module("ref_param_example")
> mod.add_include('"classes.hh"')
> a = mod.add_class("A")
> b = mod.add_class("B", allow_subclassing=True)
> a.add_constructor([param("int", "val")])
> b.add_constructor([])
> b.add_method("some_virtual_method", None, [Parameter.new("A&", "a",
> direction=Parameter.DIRECTION_INOUT)], is_const=True, is_virtual=True)
>
> Now the generated code contains the following function for the helper class
> required since we're allowing subclassing:
>
> void
> PyB__PythonHelper::some_virtual_method(A & a) const
> {
> PyGILState_STATE __py_gil_state;
> B *self_obj_before;
> PyObject *py_retval;
> PyA *py_A;
>
> __py_gil_state = (PyEval_ThreadsInitialized() ? PyGILState_Ensure() :
> (PyGILState_STATE) 0);
> if (!PyObject_HasAttrString(m_pyself, (char *) "_some_virtual_method"))
> {
> B::some_virtual_method(a);
> if (PyEval_ThreadsInitialized())
> PyGILState_Release(__py_gil_state);
> return;
> }
> self_obj_before = reinterpret_cast< PyB* >(m_pyself)->obj;
> reinterpret_cast< PyB* >(m_pyself)->obj = const_cast< B* >((const B*)
> this);
> py_A = PyObject_New(PyA, &PyA_Type);
> py_A->obj = &(a);
> py_retval = PyObject_CallMethod(m_pyself, (char *)
> "_some_virtual_method", (char *) "O", py_A);
> if (py_retval == NULL) {
> PyErr_Print();
> Py_DECREF(py_A);
> reinterpret_cast< PyB* >(m_pyself)->obj = self_obj_before;
> if (PyEval_ThreadsInitialized())
> PyGILState_Release(__py_gil_state);
> return;
> }
> if (py_retval != Py_None) {
> PyErr_SetString(PyExc_TypeError, "function/method should return
> None");
> Py_DECREF(py_retval);
> Py_DECREF(py_A);
> reinterpret_cast< PyB* >(m_pyself)->obj = self_obj_before;
> if (PyEval_ThreadsInitialized())
> PyGILState_Release(__py_gil_state);
> return;
> }
> if (py_A->ob_refcnt == 1)
> py_A->obj = NULL;
> else{
>
> py_A->obj = new A(a);
> }
> Py_DECREF(py_retval);
> Py_DECREF(py_A);
> reinterpret_cast< PyB* >(m_pyself)->obj = self_obj_before;
> if (PyEval_ThreadsInitialized())
> PyGILState_Release(__py_gil_state);
> return;
> }
>
> You can see the line near the end here that is trying to make a copy of the
> "a" argument with "py_A->obj = new A(a);", which isn't what we want. Why is
> it trying to do that anyway? This was all generated with pybindgen 0.10.0
> by the way -- is there a more recent version that will avoid this problem?
>
Ah, right. The thing is, the code tries to make a copy of the object to
give to the python wrapper in case it appears the python code kept a
reference to the wrapper.
I need to fix pybindgen to, if the class has no copy constructor keep the
wrapper->obj pointer NULL instead of giving it a copy.
The fix has been pushed to the bazaar branch. See
https://code.launchpad.net/~gjc/pybindgen/trunk
>
> Thanks!
>
> Mike.
>
> On Jun 28, 2009, at 8:19 AM, Gustavo Carneiro wrote:
>
> After starting to look at this issue, I realized that this solution is
> already implemented actually, but I had forgotten! :P
>
> You need to tell pybindgen that the reference parameter is INOUT, thus:
>
> ReferenceManipulator.add_method('do_manipulate_object', 'void',
> [Parameter.new('ManipulatedObject&',
> 'obj', direction=Parameter.DIRECTION_INOUT)],
> is_virtual=True, is_pure_virtual=True)
>
> Then everything works as expected. I am closing the bug by merely adding a
> unit test to cover this problem. Should work in pybindgen 0.10 as well.
>
> Take care,
>
> --
> Gustavo J. A. M. Carneiro
> INESC Porto, Telecommunications and Multimedia Unit
> "The universe is always one step beyond logic." -- Frank Herbert
>
>
>
> _______________________________________________
> Cplusplus-sig mailing list
> Cplusplus-sig at python.org
> http://mail.python.org/mailman/listinfo/cplusplus-sig
>
--
Gustavo J. A. M. Carneiro
INESC Porto, Telecommunications and Multimedia Unit
"The universe is always one step beyond logic." -- Frank Herbert
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20090630/d89192f6/attachment.htm>
More information about the Cplusplus-sig
mailing list