[C++-sig] boost::python constructing object from PyObject *

David Abrahams dave at boostpro.com
Wed Oct 29 21:55:48 CET 2008


on Wed Oct 29 2008, Hans Meine <hans_meine-AT-gmx.net> wrote:

> On Mittwoch 29 Oktober 2008, Dan Eloff wrote:
>> When creating an object from a PyObject *, how do you distinguish
>> between a PyObject pointer that is a new reference (must not be
>> increfed, but must be decrefed) versus a PyObject * that is a borrowed
>> reference? (should be increfed and decrefed)
>>
>> A very simple question for which there is no documented answer,
>> conflicting answers in the archives of this mailing list, and hours of
>> googling has turned up conflicting information.
>>
>> The best I could find was object(borrowed(ptr)) for new references and
>> object(handle<>(ptr)) for borrowed pointers. I'm not sure if that is
>> accurate, but if so that deserves a nomination for a terrible
>> interface award.
>>
>> Please someone put me out of my misery. What's the interface for this?
>
> IIRC I have complained about this in the past, too.  I think it was actually 
> discussed in the BPL tutorial (and only there AFAIK), but was eventually 
> deleted (probably because it was not the best place for that kind of 
> information).
>
> Actually, I have the same question as you, and the same impression that the 
> above two ways are the "correct" ways.  Err, no - you did swap the two, 
> right?


Guidelines:

  - handle, essentially a smart pointer.  Use when necessary.

    * a handle<> can be NULL, and maintains a reference count on the
      object it points to

    * handle<> y(null_ok(x)) allows y to become NULL

    * handle<> y(x), where x is not the result of null_ok, never results
      in a NULL y.  An exception will be thrown if x is NULL

    * handle<> y(borrowed(x)) presumes that *x is borrowed and thus
      increments its reference count. 

    * handle<> y(x), where x is not the result of borrowed, presumes
      that someone has already incremented the reference count on *x for
      us.

    * you can combine borrowed and null_ok in any order, so 

        handle<> y(borrowed(null_ok(x))) 

      and

        handle<> y(null_ok(borrowed(x))) 

      are equivalent.

  - object, a higher-level notion.  Use wherever possible.

    * an object can't be constructed from a raw PyObject* because
      there's no information in that type about whether the refcount has
      been incremented for this additional reference

    * an object can only be constructed from a handle<>.  Other
      interfaces are not for public consumption and thus not
      documented.  Use at your own peril.

    * an instance of object always "points to" something (maybe None).
      If the constructor argument (handle) is NULL, an exception will be
      thrown.
    
> Looking back at my code, I think I used boost::python::detail::new_reference.
>
> And for turning a Foo* pointer to an object of an exported class Foo, I used 
> something as ugly as:
> bp::detail::new_reference(typename manage_new_object::apply<T *>::type()(p)
>
> AFAICS, I repeated my questions a total of three times (in the "How about 
> class_<...>.enable_copy() ?" thead), but nobody answered so far.

The above should be a complete guide.  Any questions?

-- 
Dave Abrahams
BoostPro Computing
http://www.boostpro.com


More information about the Cplusplus-sig mailing list