[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