Pool of QObject instances

Pool of QObject instances

本文关键字:instances QObject of Pool      更新时间:2023-10-16

我有一个问题,我不知道如何解决…

我们有泛型对象池。当对象被请求时,池返回QSharedPointer到第一个可用的实例,并指定自定义Deleter。删除器只在QSharedPointer实例refcount为0时返回对象到池。对于普通对象,一切都工作得很好。当在Qt 5中编译时,它也可以很好地用于QObject继承者。

然而,如果在Qt 4.6中编译-问题开始:当第二次请求相同的对象时-应用程序退出并出现错误:

"QSharedPointer:指针xxx已经有引用计数"

我写了简单的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

在Qt 4.6中编译时肯定会失败。再次:在QT 5.x中工作良好。

查看Qt源代码,它揭示了4.6在QObject中初始化内部ref计数器,当这个QObject被用作QSharedPointer参数时。这样做是为了确保没有两个智能指针指向同一个对象,它只在析构函数中被重置。

QObject实例包装成智能指针时,Qt5不检查ref计数器的值,因此它工作。

有人知道旧Qt版本的任何解决方案吗?是否有任何方法可以完全重置内部Qt状态,包括refcounter ?

假设你有一个池来避免内存分配和释放,你应该只分配一次内存,然后在请求和返回"new"对象时显式调用构造函数和析构函数。

/* 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);

您只能从QObject创建QSharedPointer一次之后,您将需要复制现有的QSharedPointer实例

根据Qt 4和5文档:

QSharedPointer 将在指针超出作用域时删除它所持有的指针,前提是没有其他QSharedPointer对象引用它。

所以你的样本行为如下:

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)

使用QWeakPointer不会删除QObject和断言:

"QSharedPointer:指针xxx已经有引用计数"

是为了确保您不会意外创建多个删除器(这确实很安全,我使用的是QSharedPointer,但意味着QWeakPointer),但它有时确实会妨碍。