我对QTreeView的自定义模型(基类为QTreeView)的实现有问题。
简而言之,在调用beginRemoveRows()之后,QAbstractItemModel用从QModelIndex::internalPointer()返回悬空指针的QModelIndex调用我的parent()实现。下面是调用堆栈:

好的,尽量把代码的一小部分张贴出来。
我正在和下一棵树合作:

以下是包含包含文件的项目的解决方案。
FileItem 模型包含类的实例:
class FileItem;
typedef QSharedPointer<FileItem> FileItemPtr;
class FileItem
{
public:
explicit FileItem(File* file, FileItem* parentItem = nullptr);
...
FileItem* child(int row); // returns @row element of @childItems_ vector
FileItem* parentItem() const; // returns @parentItem_
void removeChild(int row); // removes @row element from @childItems_ vector
private:
QVector<FileItemPtr> childItems_;
FileItem* parentItem_;
...
};这里是模型的(**FilesModel**)主要功能:
class FilesModel :
public QAbstractItemModel
{
...
private:
QModelIndex index(
int row,
int column = 0,
const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex& index) const Q_DECL_OVERRIDE;
// returns corresponding childCount() for valid @parent's internalPointer()
int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE
{
Q_UNUSED(parent);
return 1;
}
private:
QVector<FileItemPtr> items_;
}QModelIndex**'s创建:**
QModelIndex FilesModel::index(
int row,
int column /*= 0*/,
const QModelIndex& parent /*= QModelIndex()*/) const
{
if(!hasIndex(row, column, parent))
return invalidIndex();
if(!parent.isValid()) // If, parent is invalid, then @row is our items_[row]
{
if(row < items_.size())
{
FileItem* item = items_.value(row).data();
// Pass @item as QModelIndex's internal pointer
return createIndex(row, column, item);
}
return invalidIndex();
}
FileItem* parentItem = static_cast<FileItem*>(parent.internalPointer());
FileItem* childItem = parentItem->child(row);
if(childItem)
// Pass @childItem as QModelIndex's internal pointer
return createIndex(row, column, childItem);
else
return invalidIndex();
}获得项目的父级:
QModelIndex FilesModel::parent(const QModelIndex& index) const
{
if(!index.isValid())
return invalidIndex();
FileItem* childItem = static_cast<FileItem*>(index.internalPointer());
///////////////////////////////////////////////////////////////////////////
//
// @childItem is dandling poiner after call of beginRemoveRows()
// for root item. See FilesModel::removeRows()
//
FileItem* parentItem = childItem->parentItem();
if(parentItem == nullptr)
return invalidIndex();
return createIndex(parentItem->row(), 0, parentItem);
}FilesModel::removeRows()
好的,当我尝试删除任何文件(项目的子项)和任何项目(解决方案的子项)时,FilesModel::removeRows()的下一个impl工作得很好。但是,当我删除解决方案项(关于根元素)时,我遇到了问题开头描述的情况:QAbstractItemModel 用 QModelIndex 调用函数,该函数从 QModelIndex::internalPointer(),返回悬空指针,但我将有效的指针传递给createIndex(),并且从不使用QModelIndex::internalPointer()的显式删除。
Ok,下面是移除项:
bool FilesModel::removeRows(int row, int count, const QModelIndex& parent /*= QModelIndex()*/)
{
Q_ASSERT(count > 0);
Q_ASSERT(row >= 0);
if(parent.isValid()) // Child items of @items_
{
// This branch works fine
for(int r = row; r < (row + count); ++r)
{
QModelIndex idxRemove = parent.child(r, 0);
Q_ASSERT(idxRemove.isValid());
FileItem* fiRemove = static_cast<FileItem*>(idxRemove.internalPointer());
Q_ASSERT(fiRemove);
if(idxRemove.child(0, 0).isValid()) // Has childrens
{
bool childRemoved = removeRows(0, fiRemove->childCount(), idxRemove);
Q_ASSERT(childRemoved);
}
}
FileItem* fiParent = static_cast<FileItem*>(parent.internalPointer());
Q_ASSERT(fiParent->childCount() >= (row + count - 1));
beginRemoveRows(parent, row, row + count - 1);
int childToRemove = row;
for(int r = row; r < (row + count); ++r)
fiParent->removeChild(childToRemove);
endRemoveRows();
return true;
}
else // Removing @items_
{
// Here is problem branch
Q_ASSERT(rowCount() >= (row + count - 1));
for(int r = row; r < (row + count); ++r)
{
FileItem* slnItem = items_.value(r).data();
bool projectRemoved = removeRows(0, slnItem->childCount(), index(r));
Q_ASSERT(projectRemoved);
}
///////////////////////////////////////////////////////////////////////
// This call to beginRemoveRows() cause call of parent() function
// with invalid QModelIndex::internalPointer()
//
beginRemoveRows(QModelIndex(), row, row + count - 1);
int slnRemove = row;
for(int r = row; r < (row + count); ++r)
items_.remove(slnRemove);
endRemoveRows();
return true;
}
return false;
}谁知道问题出在哪里?
我正在用一个GUI线程来处理这个模型。我在Windows上有QT5.4.0。谢谢
更新: validateItem()只是检查指针值以捕捉来自QModelView::internalPointer()的抖动指针的问题。
void FileItem::validateItem() const
{
Q_ASSERT((reinterpret_cast<size_t>(this) > 0x1000)
&& "Invalid item");
for(const FileItemPtr& child : childItems_)
child->validateItem();
}因此,为了找到问题,我的FilesModel::parent()如下所示:
QModelIndex FilesModel::parent(const QModelIndex& index) const
{
if(!index.isValid())
return invalidIndex();
FileItem* childItem = static_cast<FileItem*>(index.internalPointer());
#if !defined(NDEBUG)
// Try to understand, if @childItem is OK
childItem->validateItem();
#endif
...
}发布于 2015-01-05 13:08:39
您正在显示的调用堆栈表明您的代码中的断言失败了,因此您应该知道问题出在哪里!
检查FileItem::validateItem行nr 316中的代码,看看是什么问题。(再次发生崩溃时,只需在调用堆栈视图中单击适当的(第二项)项)
关于最新情况:
UPDATE: validateItem()只是检查指针值,以捕捉QModelView::internalPointer()中的指针抖动问题 Q_ASSERT((reinterpret_cast(this) > 0x1000)
见鬼?谁告诉你这是正确的检测方法?悬空指针并不意味着指针有一些特定的值!
https://stackoverflow.com/questions/27779661
复制相似问题