[PyKDE] boost::shared_ptr

Jim Bublitz jbublitz at nwinternet.com
Tue Mar 22 08:23:16 GMT 2005


On Monday 21 March 2005 09:29, James Emerton wrote:
> I am rather new to PyQt/SIP and looking for a hint or two.

> The application in which I am embedding Python has a fairly extensive
> (non-Qt) API, with a Qt UI sitting on top.  The API makes extensive use
> of refcounted smart pointers (boost::shared_ptr) to abstract interface
> classes.

> So far, I believe that I can use the %MethodCode directive to override
> factory methods, and dynamically allocate a new instance of  the smart
> pointer, which would increment the shared_ptr reference count and
> prevent deletion so long as the python ref count was non zero.  The
> problem with this approach seems that I would also have to write
> %MethodCode to access every method in the wrapped class!

It makes a difference if boost::shared_ptr is used as a base class or as a 
return value from a factory function. Here's an example of the latter from 
PyKDE (.sip file):

class KSharedConfig : KConfig, KShared
{
public:
    ...
    typedef KSharedPtr<KSharedConfig> Ptr;
    static KSharedConfig::Ptr openConfig (const QString&, bool = 0, bool = 1);
    ...
}

...

%MappedType KSharedConfig::Ptr
//converts KSharedConfig
{
%TypeHeaderCode
#include <ksharedptr.h>
#include <kconfig.h>
#include <sipkdecoreKSharedConfig.h>
%End

%ConvertFromTypeCode
    // Convert to a Python instance

    if (!sipCpp)
        return NULL;

    // the following line of code is wrapped - basically:
    // A<B> *cPtr = new A<B>(*(A<B>*) sipCpp)
    KSharedPtr<KSharedConfig> *cPtr = new KSharedPtr<KSharedConfig>   
             (*(KSharedPtr<KSharedConfig> *)sipCpp);

    // Gets the actual instance of KSharedConfig
    KSharedConfig *cpp = cPtr->data ();

    PyObject *obj = sipMapCppToSelf (cpp, sipClass_KSharedConfig);

    return obj;
%End

%ConvertToTypeCode
    // Convert a Python instance to a Ptr on the heap.

    if (sipIsErr == NULL)
        return PyInstance_Check(sipPy);

    int iserr = 0;
    KSharedConfig *cpp = 
      (KSharedConfig *)sipForceConvertTo_KSharedConfig (sipPy, &iserr);

    if (iserr)
    {
        *sipIsErr = 1;
        return 0;
    }

    *sipCppPtr = new KSharedPtr<KSharedConfig> (cpp);

    return 1;
%End
};

The %MappedType conversion functions take care of passing something useful to 
Python or C++. You can call them from %MethodCode too. Look at the 
corresponding h files sip generates for the function names. 

From Python's point of view, openConfig just returns an instance of 
KSharedConfig (from the %ConvertFromTypeCode block). Ptr can also be used as 
a Python argument to an eventual C++ call  (the %ConvertToTypeCode block).  
In other words, the %MappedType code will handle the conversion any place Ptr 
is used in the sip files.

It seems to me Python is taking care of all of the ref counting in this case - 
there might be pathological cases where either the C++ instance of the 
template type or the Python instance get orphaned (no corresponding object on 
"the other side"). Most PyKDE programs don't use these types very much 
explicitly (although the little testing I've done hasn't shown any problems 
yet). 

Allocating new objects in each conversion function seems to bypass the C++ ref 
counting feature. There's a new C++ object created each time, but I don't 
think that makes a lot of difference. The multiple references (to Python 
objects) on the Python side will be managed by Python

You can also do the same thing (more or less) with %MethodCode - I'm not sure 
why either case would require every method in a class to have %MethodCode. Do 
you have a short example of how it's being used that might require that, or 
do the methods just require the template-based type (%MappedType will handle 
that)?

It's a different problem if the template type is used as a base class. I've 
only done a couple of those - QStringList is one example, I believe (Phil's 
code that I borrow from). Look at qt/qstringlist.sip in PyQt. Basically, 
you'd ignore the base class in the sip code and add any methods required from 
the base class yourself.

Jim




More information about the PyQt mailing list