QTreeWidgetItem析构函数和QTreeWidgetItemIterator有效性

时间:2018-03-05 22:49:52

标签: c++ qt qtreewidget qtreewidgetitem

为什么删除QTreeWidgetItem *会自动推进与同一QTreeWidget关联的迭代器?在我看来的任何地方,此行为似乎都不是IMG。我希望在删除QTreeWidget *之后,迭代器不受影响(除了现在指向无效值)。相反,似乎QTreeWidget析构函数会自动推进QTreeWidget的所有迭代器。

简要介绍qt源代码,我认为这可以通过让所有迭代器在创建模型时向模型注册。然后在documented中调用QTreeItem::~QTreeItem调用QTreeModel::beginRemoveItems()来推进所有迭代器。

除了直接检查所有QT来源外,你怎么知道这种情况发生了?所有QT迭代器都是这样做的吗?我对STL迭代器的经验比对QT的经验更多,也许这就是为什么我发现这是如此意外。

以下代码演示了此行为:

    #include <QTreeWidget>
    #include <QDebug>
    #include <QApplication>

    int main(int argc, char **argv)
    {
        QApplication a( argc, argv );
        QTreeWidget * tw_1 = new QTreeWidget();
        QTreeWidget * tw_2 = new QTreeWidget();
        for(int i = 1; i <=5; i++)
        {
                tw_1->addTopLevelItem(new QTreeWidgetItem(QStringList(QString("Item %1").arg(i))));
                tw_2->addTopLevelItem(new QTreeWidgetItem(QStringList(QString("Item %1").arg(i))));
        }

        {
        qDebug() << "Elements in Tree Widget 1";
        QTreeWidgetItemIterator it(tw_1);
        while(*it)
        {
                qDebug() << "\t" << (*it)->text(0);
                ++it;
        }

        //Delete the items while iterating over the tree
        QTreeWidgetItemIterator ii(tw_1);
        while(*ii)
        {
                delete *ii;
        }

        qDebug() << "Elements remaining in Tree Widget 1";
        QTreeWidgetItemIterator itt(tw_1);
        while(*itt)
        {
                qDebug() << (*itt)->text(0);
                ++itt;
        }
        }

        {
        qDebug() << "Elements in Tree Widget 2";
        QTreeWidgetItemIterator it(tw_2);
        while(*it)
        {
                qDebug() << "\t" << (*it)->text(0);
                ++it;
        }

        //Delete the items while iterating over the tree
        QTreeWidgetItemIterator ii(tw_2);
        while(*ii)
        {
                delete *ii;
                ++ii;
        }
           qDebug() << "Elements remaining in Tree Widget 2";
        QTreeWidgetItemIterator itt(tw_2);
        while(*itt)
        {                                                                                                                     
                qDebug() << (*itt)->text(0);                                                                                  
                ++itt;                                                                                                        
        }                                                                                                                     
        }                                                                                                                     
}  

这会产生输出:

Elements in Tree Widget 1 
     "Item 1" 
     "Item 2" 
     "Item 3" 
     "Item 4" 
     "Item 5" 
Elements remaining in Tree Widget 1 
Elements in Tree Widget 2 
     "Item 1" 
     "Item 2" 
     "Item 3" 
     "Item 4" 
     "Item 5" 
Elements remaining in Tree Widget 2 
     "Item 2" 
     "Item 4"  

1 个答案:

答案 0 :(得分:0)

迭代器在QList中定义为QTreeModel

QList是基于索引的。如果删除了具有当前索引的项目,则下一个项目将成为当前索引。

请参阅以下链接。您将看到迭代器的定义,如下所示。

https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qtreewidget_p.h.html#QTreeModel

你会看到像这样的定义

QList<QTreeWidgetItemIterator*> iterators;

现在,当你在迭代器上调用delete时,会调用QTreeWidgetItemIterator的析构函数。

https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qtreewidgetitemiterator.cpp.html#_ZN23QTreeWidgetItemIteratorD1Ev

QTreeWidgetItemIterator::~QTreeWidgetItemIterator() 
{ 
    d_func()->m_model->iterators.removeAll(this); 
} 

通过注意上面的代码,使用QList函数removeAll删除迭代器,并从列表中完全删除迭代器。

QList是基于索引的。因此,如果删除了具有索引3的迭代器,则下一个迭代器索引将变为3。

现在当你做++时,

下面的函数被调用,它会带来列表中的下一个项目。所以你将迭代器移到下一个项目(索引4)。

https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qtreewidgetitemiterator.cpp.html#_ZN23QTreeWidgetItemIteratorD1Ev

QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator++() 
{ 

    if (current) 
        do { 
            current = d_func()->next(current); 
        } while (current && !matchesFlags(current)); 
    return *this; 
} 
模型的

QTreeWidgetItemIterator维护为QList。因此,当您删除迭代器时,下一个迭代器将成为当前索引。所以你确实注意到了这种行为。