首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Qt::QAbstractItemModel::QAbstractItemModel()崩溃

Qt::QAbstractItemModel::QAbstractItemModel()崩溃
EN

Stack Overflow用户
提问于 2015-01-05 12:35:29
回答 1查看 3.8K关注 0票数 0

我对QTreeView的自定义模型(基类为QTreeView)的实现有问题。

简而言之,在调用beginRemoveRows()之后,QAbstractItemModel用从QModelIndex::internalPointer()返回悬空指针的QModelIndex调用我的parent()实现。下面是调用堆栈:

好的,尽量把代码的一小部分张贴出来。

我正在和下一棵树合作:

以下是包含包含文件的项目的解决方案。

FileItem 模型包含类的实例:

代码语言:javascript
复制
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**)主要功能:

代码语言:javascript
复制
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创建:**

代码语言:javascript
复制
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();
}

获得项目的父级:

代码语言:javascript
复制
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,下面是移除项:

代码语言:javascript
复制
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()的抖动指针的问题。

代码语言:javascript
复制
void FileItem::validateItem() const
{
    Q_ASSERT((reinterpret_cast<size_t>(this) > 0x1000)
        && "Invalid item");

    for(const FileItemPtr& child : childItems_)
        child->validateItem();
}

因此,为了找到问题,我的FilesModel::parent()如下所示:

代码语言:javascript
复制
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
    ...
}
EN

回答 1

Stack Overflow用户

发布于 2015-01-05 13:08:39

您正在显示的调用堆栈表明您的代码中的断言失败了,因此您应该知道问题出在哪里!

检查FileItem::validateItem行nr 316中的代码,看看是什么问题。(再次发生崩溃时,只需在调用堆栈视图中单击适当的(第二项)项)

关于最新情况:

UPDATE: validateItem()只是检查指针值,以捕捉QModelView::internalPointer()中的指针抖动问题 Q_ASSERT((reinterpret_cast(this) > 0x1000)

见鬼?谁告诉你这是正确的检测方法?悬空指针并不意味着指针有一些特定的值!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27779661

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档