[PyQt] wrapped C/C++ object of type has been deleted - yet it hasn't!

Nyall Dawson nyall.dawson at gmail.com
Tue Jul 25 08:04:15 BST 2017


On 14 July 2017 at 11:54, Nyall Dawson <nyall.dawson at gmail.com> wrote:
> Hi list,
>
> I've recently encountered an odd issue which has me stumped. I have a
> c++ method which returns a new object (QgsProcessingAlgorithm* -
> (which is not a QObject)), and the method is marked with a /Factory/
> annotation.
>
> Usually this approach works fine. But in this case the returned object
> behaves oddly, and frequently encounters the "wrapped C/C++ object of
> type has been deleted" error. Yet - it hasn't been deleted. I can put
> a breakpoint in the c++ destructor for the class and it's not being
> triggered. It's just that somehow the python wrapper has been mislead
> into thinking this has occurred.
>
> I can scatter various checks using sip.isdeleted around the code and
> it all looks ok at first. Right up until a few references to this
> object have been made in various other python objects. And then
> boom... I suddenly get the "wrapped object has been deleted" error
> from one of these references (without the c++ destructor being called)
>
> I'm at a loss how to debug this, or what could be happening here. Any
> hints on what could be causing this? Any likely suspects?

I'm still hitting this issue, but after doing a bunch of digging I
think I've narrowed down my issue.

If I have a  c++ class:

class MyClass
{

  public:

    MyClass() {}

    MyClass *create() const
    {
          MyClass * newInstance = createInstance();
          // do some common stuff to newInstance here
          return newInstance;
     }

  protected:

    virtual MyClass *createInstance() const = 0;

};

With the accompanying sip definition:


class MyClass
{

%TypeHeaderCode
#include "myclass.h"
%End
  public:

    MyClass();

    MyClass *create() const /Factory/;

  protected:

    virtual MyClasss *createInstance() const = 0 /Factory/;

};


(i.e. subclasses must implement createInstance to return a new copy of
the class, which is called by create() to do some common setup tasks
on the instance before returning it)

This works OK if the MyClass subclass is implemented in c++ - python
code can call create() and everything looks good. The returned object
is owned by Python.

But if I make a MyClass subclass in Python:

class x(MyClass):

    def __init__(self):
        MyClass.__init__(self)

    def createInstance(self):
        new = x()
        return new

Then things start to go strange. Calling create on an instance of this
python subclass returns <MyClass object at 0x...>, instead of the
expected <x object at 0x....>.

I suspect I'm misusing the /Factory/ annotation for createInstance()
here. But I can't see what the correct annotation should be. Any tips?

Nyall


More information about the PyQt mailing list