QObject实例池

4

我遇到了一个问题,不确定该如何解决...

我们有一个通用的对象池。当请求对象时,池会返回指向第一个可用实例的 QSharedPointer,并指定自定义删除器。删除器仅在 QSharedPointer 实例引用计数为 0 时将对象返回到池中。 对于普通对象,一切正常工作。如果编译时使用的是 Qt 5,则对于继承自 QObject 的对象也可以正常工作。

然而,在使用 Qt 4.6 编译时,问题就开始出现了:当请求同一对象的第二个实例时,应用程序会因以下错误而退出:

"QSharedPointer: pointer xxx already has reference counting"

我编写了一个简单的测试:

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用作QSharedPointer参数时初始化了内部引用计数器。这样做是为了确保没有两个智能指针可以指向同一个对象,并且它只在析构函数中重置。

Qt5不检查QObject实例被封装到智能指针中的引用计数器值,因此它可以正常工作。

有人知道旧版本Qt的任何解决方法吗?是否有完全重置内部Qt状态(包括引用计数器)的方法?欢迎提供任何提示。


2
你能使用Qt 4.8吗?你尝试过使用4.8版本吗? - Kuba hasn't forgotten Monica
还没有尝试过,在我的虚拟机中编译QT需要很长时间,而且4.6是默认的版本。但从我在源代码中看到的情况来看,4.8的行为应该是相同的,因为检查仍然存在。 - Vlad
好的。我认为你唯一的解决方案就是黑掉你的 Qt 副本。 - Kuba hasn't forgotten Monica
我最终在目标平台上编译了QT 5,这解决了问题。 - Vlad
你考虑过使用 std::shared_ptr 吗?如果你的编译器足够新并支持它,那么它可能更适合你的需求。你的使用似乎不是 QSharedPointer 设计的主要用途,因此 Qt 的未来更改可能会带来一些意外。 - hyde
2个回答

0
假设您有一个池来避免内存分配和释放,您应该仅分配一次内存,然后在请求和返回“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);

0

你只能从 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),但有时它会妨碍。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接