Convert std::shared_ptr into QPointer

1.2k views Asked by At

Our application is VERY poorly designed - it uses both std::shared_ptr and QObject parent-child relationship to manage some of our objects. This leads to segfaults when QObject::~QObject deletes its child objects and THEN shared_ptr tries to delete it also.

We discussed this but currently see no way to fix this easily so I'll need to use few dirty hacks until we fix it.

Now what I have is a std::shared_ptr<MyObject> getMyObjectPtr() function. I need to put the result into QPointer<MyObject> - QPointers are weak pointers that merely indicate if the QObject they manage is deleted. I cannot change that function in any way, it would break the whole application.

I tried few hacks with custom dealocator but that doesn't seem to work.

// get the shared_ptr from inacessible API
std::shared_ptr<MyObject> oldPtr(getMyObjectPtr());
// create a new pointer that never deletes it's value
std::shared_ptr<MyObject> newPtr(nullptr, [](MyObject*) {});
// Move pointer from old to new non-deleting ptr
newPtr.swap(oldPtr);
QPointer<MyObject> qptr(newPtr.get());

However this way, the pointer gets deleted once my function ends. Presumably, the custom dealocator moves along with the data.

1

There are 1 answers

0
Jeremy Friesner On BEST ANSWER

I don't think there is any good solution to this problem, other than to start refactoring your code so that any given object is either managed via QObject-style parent/child relationships, or shared_ptr<> reference counting -- but never both in the same object. The two approaches are just too different from each other to easily reconcile.

That said, one thing that you might be able to do in order to accomplish the above without too much redesign is this: instead of having a shared_ptr<> that points to your QObject, make the shared_ptr point to a (non-QObject-based), shared_ptr-managed sub-object of the QObject.

That is, instead of this:

class MyQObject : public QObject 
{
public:
   MyQObject(int x, int y, int z, QObject * parent)
      : QObject(parent), m_x, m_y, m_z {/* empty */}

   int getX() const {return m_x;}
   int getY() const {return m_y;}
   int getZ() const {return m_z;}

private:
   int m_x, m_y, m_z;
};

[...]

QObject * parent = new QObject;
shared_ptr<MyQObject> ptr(new MyQObject(1,2,3,parent));   // d'oh!  trouble!

do something like this:

class MyData
{
public:
   MyData(int x, int y, int z) : m_x(x), m_y(y), m_z(z)

   int getX() const {return m_x;}
   int getY() const {return m_y;}
   int getZ() const {return m_z;}

private:
   int m_x, m_y, m_z;
};

class MyQObject : public QObject
{
public:
   MyQObject(int x, int y, int z, QObject * parent)
      : QObject(parent), m_data(make_shared<MyData>(x,y,z)) {/* empty */}

   int getX() const {return m_data->getX();}
   int getY() const {return m_data->getY();}
   int getZ() const {return m_data->getZ();}

   shared_ptr<MyData> getData() {return m_data;}

private:
   shared_ptr<MyData> m_data;
};

[...]

QObject * parent = new QObject;
QObject * myObj = new MyQObject(1,2,3,parent));
shared_ptr<MyData> ptr(myObj->getData());   // no problem!

That way your Qt-style code has access to both the QObject and the MyData, while the shared_ptr-style code has access to the MyData. (Of course, if your shared_ptr-style code needs also access to the QObject itself, you're probably out of luck, since Qt will decide when and where to delete the QObject and won't respect the shared_ptr semantics)