4

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

我们有通用对象池。当请求对象时,池返回QSharedPointer到第一个可用实例,并指定了自定义 Deleter。当QSharedPointer实例引用计数为 0 时,删除器只是将对象返回到池中。对于普通对象,一切正常。QObject在 Qt 5 中编译时,它也适用于后继者。

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

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

我写了简单的测试:

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 计数器。这样做是为了确保没有两个智能指针可以指向同一个对象,并且它只会在析构函数中被重置。QObjectQSharedPointer

当实例被包装到智能指针中时,Qt5 不会检查 ref 计数器值QObject,因此它可以工作。

有谁知道旧 Qt 版本的任何解决方法?有什么方法可以完全重置内部 Qt 状态,包括参考计数器?任何提示都非常受欢迎。

4

2 回答 2

0

假设您有池以避免内存分配和释放,您应该只分配一次内存,然后在请求并返回“新”对象时显式调用构造函数和析构函数。

/* 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);
于 2014-08-11T18:08:15.657 回答
0

您只能QSharedPointerQObject 后者创建一次,您需要复制该现有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不会删除QObjectand 断言:

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

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

于 2018-11-04T12:50:44.467 回答