Pool of QObject instances

1.4k Views Asked by At

I got a problem I'm not sure how to solve..

We have generic objects pool. When object is requested the pool returns QSharedPointer to the first available instance, with custom Deleter specified. The deleter just returns object to the pool when QSharedPointer instance ref count is 0. Everything works just fine for plain objects. It also works fine for QObject successors, when compiled in Qt 5.

However, if compiled in Qt 4.6 - the problems begin: when same object is requested second time - application exits with an error:

"QSharedPointer: pointer xxx already has reference counting"

I wrote simple test:

QObject* obj = new QObject();
QSharedPointer<QObject> p(obj, deleter); // deleter here does nothing
p.clear();
QSharedPointer<QObject> p2(obj, deleter); // this crashes the app

And surely this fails when compiled in Qt 4.6. Again: works fine in QT 5.x.

Looking into the Qt source code it revealed 4.6 initializes internal ref counter in QObject when this QObject is used as a QSharedPointer parameter. This is done to make sure no two smart pointers can point to the same object and it only gets reset in the destructor.

Qt5 does not check ref counter value when QObject instance is wrapped into smart pointer, thus it works.

Does anyone know any workaround for older Qt version? Is the any way to completely reset internal Qt status, including ref counter? Any hints are very welcome.

2

There are 2 best solutions below

0
On

you are only once allowed to create QSharedPointer from QObject latter you will need to copy that existing QSharedPointer instance

according to Qt 4 and 5 docs:

QSharedPointer will delete the pointer it is holding when it goes out of scope, provided no other QSharedPointer objects are referencing it.

so your samples behavior is like below:

QObject* obj = new QObject();
QSharedPointer<QObject> p(obj, deleter); // deleter here does attach to "obj"
p.clear(); //this does cause delete of "obj"
QSharedPointer<QObject> p2(obj, deleter); // using deleted pointer will cause crash (if you are lucky XD)

using QWeakPointer will not delete the QObject and the assertion:

"QSharedPointer: pointer xxx already has reference counting"

is to ensure you do not create multiple deleters by accident (which did safe my day, I was using QSharedPointer but meant QWeakPointer) but it does get sometimes in the way.

0
On

Assuming that you have pool to avoid memory allocation and deallocation you should allocate memory only once and then call constructor and destructor explicitly when you request and return "new" object.

/* deleter calls destructor explicitly when return object to pool */
void deleter(QObject *object) {
    object->~QObject();
    mark_as_available();
}

/* allocate (one object) pool memory without calling constructor*/
QObject *object = ::operator new(sizeof(QObject));

/* request object - calling constructor on already allocated memory */
mark_as_taken();
return QSharedPointer(::new (object) QObject, &deleter);

/* deallocate pool memory without calling destructor */
::operator delete(object);