[C++-sig] Custom smart pointer with same behaviour as shared_ptr

john haddon theboyhaddon at hotmail.com
Sat Jan 19 21:18:28 CET 2008


> 
> I am not sure I follow here.
> 
> My hierarchy is
> 
> base class A
> B : A
> C : B
> 
> then I call a function returning an intrusive_ptr(new C()) into c
> 
> >>> type(c)
> 
> 
> So Python can tell that the object is of type C even if it was returned as a pointer to the base 
> class A.
> 
> Other point: please correct me if I am wrong.
> I need to register every class I want to be able to cast to (i.e. every class I want to accept as 
> argument).
> So in that case I need to add both
> 
> INTRUSIVE_PTR_PATCH(B, B_class);
> and
> INTRUSIVE_PTR_PATCH(C, C_class);
> 
> so that my functions can take intrusive_ptr of type B and C.
> No need to do it with A.

correct - that should be all you need to solve the downcasting problem. everything else i mentioned
relates to other problems you might see later - i've expanded on those a bit below.
 
>> 
>> We are working around this problem in two ways. Firstly we have an ugly 
>> isSame() method bound for object
>> to be used instead of "is". Secondly we have another to_python converter 
>> for use when we wrap classes. This
>> solves the object identity problem by keeping a mapping from C++ objects 
>> to python objects. You can see that
>> here :
>> 
>> http://cortex-vfx.googlecode.com/svn/trunk/include/IECore/bindings/WrapperToPython.h
>> 
>> I suspect the two solutions could be combined into one general solution, 
>> but currently it's working just
>> well enough so we've left it there...
> 
> Here, first I need to understand the problem, then I pass to your solution.
> Is it a general problem, or something relative to intrusive_ptr, that would not be there, had you 
> used boost::shared_ptr?

the problem is this - say you bind this function :

intrusive_ptr x( intrusive_ptr b ) { return b; }

then this python code fails :

b = B()
b2 = x( b )
assert( b is b2 ) # fails

although both b and b2 correctly refer to the same c++ object, they refer to two different python
instances - what x should really do is return the same PyObject that was being used to hold b in the
first place. i believe there's some magic in boost::python that solves this problem as long as you're
using shared_ptr (although you might want to test that), but the patch i posted for the downcasting
of intrusive_ptr doesn't address it...

we've addressed the issue only for classes we wrap during binding - as we can easily store a mapping
between the c++ pointer and the PyObject * and use that in our to_python function...this is what you
see in this file :

http://cortex-vfx.googlecode.com/svn/trunk/include/IECore/bindings/WrapperToPython.h

that file also refers to the WrapperGarbageCollector class we use in the same project. we found there
were memory management issues using the boost::wrapper mechanism - i don't recall the specifics
but it was either that wrapped objects would never be garbage collected, or that the python half of the
wrapped object could die before the c++ half. to tie the lifetimes of the two halves of the objects together
they each must have a reference to the other, but that results in a circular reference and hence no
collection - WrapperGarbageCollector periodically trawls through the wrapped instances and breaks any
such cycles when necessary. depending on whether or not you use wrapping you may want to incorporate
something like that too...

cheers...
john















_________________________________________________________________




More information about the Cplusplus-sig mailing list