[C++-sig] Python __init__ that copies internal reference, boost.python

Branan Purvine-Riley branan at gmail.com
Tue Aug 17 01:21:17 CEST 2010


On Monday 16 August 2010 14:49:04 Jim Bosch wrote:
> On 08/16/2010 02:33 PM, Branan Purvine-Riley wrote:
> > I'm working on replacing hand-rolled python bindings with boost.python.
> > 
> > Unfortunately, I've hit a bit of a snag at a particular construct:
> >    a = someFunction(...) # returns an instance of myClass
> >    b = myClass(a)
> > 
> > In the current bindings, this creates a new python object that references
> > the same internal C++ object. It's effectively no-op, and I have no idea
> > why it was written that way in the first place, but I have to maintain
> > API compatibility.
> > 
> > That being the case, how do I implement this in boost.python? I
> > considered replacing __init__, but it seems if I implement that as a
> > standalone function rather than a constructor, boost has already created
> > a new C++ instance for me, so that's too late. I'm not really sure what
> > else to try.
> 
> You'll want to use the make_constructor function; this takes a C++
> function returning a C++ smart pointer and creates a Python __init__
> overload.
> 
> I *think* this should work (I haven't tested it):
> 
> ----------------------------------------------
> 
> boost::shared_ptr<MyClass> construct(boost::python::object const & arg) {
>      return boost::python::extract< boost::shared_ptr<MyClass> >(arg);
> }
> 
> BOOST_PYTHON_MODULE(example) {
>      boost::python::class_<MyClass>("MyClass")
>          .def("__init__", boost::python::make_constructor(&construct))
>          ;
>      boost::python::register_ptr_to_python<
>          boost::shared_ptr<MyClass>
> 
>      >();
> 
> }
> 

That's definitely on the right track. Not quite right because of some of the 
oddities of what I'm working with here. It's a game engine, and none of the 
pointers are stored in a smart pointer container of any kind. Unfortunately 
make_constructor will convert a raw ptr to an std::auto_ptr, which deletes the 
object somewhere in boost code.

What I ended up with is the following:

  template<typename T>
  struct dummy_ptr {
    dummy_ptr(T* p) : ptr(p) {}
    T* operator->() { return ptr; }
    T* ptr;
    typedef T element_type;
  };

  template<typename T>
  T* get_pointer(const dummy_ptr<T>& dummy) {
    return dummy.ptr;
  }

  template<typename T>
  dummy_ptr<T> noop_constructor(T* arg) {
    return dummy_ptr<T>(arg);
  }

 BOOST_PYTHON_MODULE(example) {
      boost::python::class_<MyClass>("MyClass")
          .def("__init__",boost::python::make_constructor(&noop_constructor<MyClass>));
      boost::python::register_ptr_to_python<dummy_ptr<MyClass> >();
 }


More information about the Cplusplus-sig mailing list