[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