[PyKDE] Re: clone member function deleting object

Phil Thompson phil at riverbankcomputing.co.uk
Wed Mar 16 09:42:36 GMT 2005


>    Using sip.transfer(), as Phil suggested, keeps the destructor of my
> object created by clone() from being destroyed.   However, my object
> is still not useable as it can't find the Python implemented methods
> when it is called from C++ after return of clone.
>
>    Poking around, I found that sipFunctionBase::sipPySelf data member
> has gotten reset to zero.   Using SIP trace and adding some printing
> in the generated sipFunctionBase.cpp file by hand, the trace back
> is...
>
>
> FunctionBase * sipFunctionBase::clone() const (this=0x083c9d90)
>   sipPySelf = 0x419c623c
> python.clone
> init_FunctionBase  sipSelf = 0x419c629c
> sipFunctionBase::sipFunctionBase(const FunctionBase&) (this=0x08406528)
>   sipPySelf = 0
>   sipCpp = 0x8406528
> python.copy
> dealloc_FunctionBase  sipSelf = 0x419c629c
>   sipIsSimple not
> const std::vector<double>& sipFunctionBase::getParameters()
> (this=0x08406528)
>   sipPySelf = 0
>
> Note
>
> - sipFunctionBase::clone() finds the Python member function and calls
>   it.  Looks ok
>
> - The sipFunctionBase copy constructor gets called followed by Python
>   __init__ method.  Looks ok
>
> - on return, dealloc_FunctionBase is called with argument of the newly
>   created instance.   It appears that sipPySelf is then set to zero!
>
> - The very first call to a member function shows indeed that the member
>   sipPySelf is a null pointer.
>
> Any ideas, suggestions?

sipPySelf is the pointer to the Python instance object. It is reset to 0
to show that it has been garbage collected. Unfortunately, as you have
found, it means the Python virtual reimplementations can no longer work.
There is a slight difference between the Python sip.transfer() and the C++
sipTransfer(). The latter creates an extra reference to the Python object
to prevent to being garbage collected - the former doesn't because the
intent was to completely divorce the Python and C++ objects. You want the
behaviour of sipTransfer() rather than sip.transfer().

There are two solutions...

I add an optional second argument to sip.transfer() that causes it to
behave like sipTransfer() - I will do this anyway in the next few days.

You use sipTransfer() - but you must call it before the Python object is
garbage collected, ie. you must provide %VirtualCatcherCode for clone().
This is probably what you want to do if you want to make life as easy as
possible for your users writing the Python reimplementations.

Phil




More information about the PyQt mailing list