[C++-sig] pybindgen: allow_subclassing option causing reference parameters to be copied?
J. Michael Owen
mikeowen at llnl.gov
Mon Jun 29 20:03:44 CEST 2009
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?
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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20090629/8656af35/attachment.htm>
More information about the Cplusplus-sig
mailing list