我设置了一个主模型(QStandardModel),一个代理模型,它改变了DisplayRole的输出,以及一个单独的表视图显示每个模型。在主模型数据中是一个用户角色,它存储一个指向另一个QObject的指针,代理模型使用该指针来获得所需的显示值。
当该变量所指向的对象被删除时,我遇到了问题。我正在处理删除主模型通过销毁(QObject*)信号。在槽中,我搜索整个模型,查找指向该对象的任何项并删除引用。
该部分本身工作得很好,但我也连接到代理模型的ondatachchanged(…)信号,我在代理模型上调用resizeColumnsToContents()。然后调用代理的data()函数。这里我检查项目是否有指针,如果有,则从对象中获取一些信息以供显示。
所有这些的结果变成:
- 对象即将被删除触发销毁(…)信号
- 主模型查找使用删除对象的任何项,并调用setData来删除引用
- Tableview捕获代理模型的ondatachchanged信号并调整列的大小 代理模型的数据(…)被调用。它检查主模型中的项是否有对象指针,如果有,则显示对象中的值。
问题是,在步骤4中,主模型中的项目显然还没有被删除;指针地址仍然被存储。但是,指针所引用的对象此时已被删除,从而导致段错误。
我如何修复我的设置,以确保主模型完成删除指针引用代理模型尝试更新之前?
同样,这里是相关部分的伪代码:
// elsewhere
Object *someObject = new QObject();
QModelIndex index = mainModel->index(0,0);
mainModel->setData(index, someObject, ObjectPtrRole);
// do stuff
delete someObject; // Qt is actually doing this, I'm not doing it explicitly
// MainModel
void MainModel::onObjectDestroyed(QObject *obj)
{
// iterating over all model items
// if item has pointer to obj
item->setData(QVariant::fromValue(NULL), ObjectPtrRole));
}
// receives onDataChanged signal
void onProxyModelDataChanged(...)
{
ui->tblProxyView->reseizeColumnsToContents();
}
void ProxyModel::data(const QModelIndex &index, int role) const
{
QModelIndex srcIndex = mapToSource(index);
if(role == Qt::DisplayRole)
{
QVariant v = sourceModel()->data(srcIndex, ObjectPtrRole);
Object *ptr = qvariant_cast<Object*>(v);
if(ptr != NULL)
return ptr->getDisplayData();
else
return sourceModel->data(srcIndex, role);
}
}
问题是ptr不是NULL,但引用的对象被删除,在时间ProxyModel::data(…)被调用,所以我结束了一个段错误。
要避免与QObject
实例的悬空指针解引用,可以做以下两件事之一:
-
使用
object->deleteLater
-一旦控件返回到事件循环,对象将被删除。这种功能也被称为自动发布池。 -
使用
QPointer
。它会在删除对象时将自身设置为null,因此您可以在使用前检查它。