4

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.

laylarenee
  • 3,276
  • 7
  • 32
  • 40
Vlad
  • 301
  • 4
  • 10
  • 2
    Can you use Qt 4.8, and have you tried it with 4.8? – Kuba hasn't forgotten Monica Jul 02 '14 at 18:05
  • Haven't tried yet, it takes ages to compile QT in my virtual machine and 4.6 comes by default. But from what I've seen in the source code - 4.8 will behave the same since the check is still there. – Vlad Jul 02 '14 at 20:32
  • OK. I think the only solution for you is to hack your copy of Qt, then. – Kuba hasn't forgotten Monica Jul 02 '14 at 21:27
  • I ended up compiling QT 5 on a target platform, this solves the issue. – Vlad Jul 06 '14 at 19:57
  • Have you considered using `std::shared_ptr` instead? It might be better fit for your need, if you have a new enough compiler that supports it. Your use seems like it's not necessarily what `QSharedPointer` was designed for, so future changes in Qt might bring surprises. – hyde Aug 11 '14 at 18:56

2 Answers2

0

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);
Mateusz Drost
  • 1,171
  • 10
  • 23
0

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.

Top-Master
  • 7,611
  • 5
  • 39
  • 71