为什么删除QTreeWidgetItem *会自动推进与同一QTreeWidget关联的迭代器?在我看的任何地方,这种行为似乎都不是documented。我希望在删除QTreeWidget *之后,迭代器不受影响(除了现在指向无效值)。相反,似乎QTreeWidget析构函数会自动推进QTreeWidget的所有迭代器。
简要介绍一下qt源代码,我认为这可以让所有迭代器在创建模型时将自己注册到模型中。然后在QTreeItem::~QTreeItem中,对QTreeModel::beginRemoveItems()的调用调用了QTreeWidgetItemIteratorPrivate::ensureValidIterator(),它推进了所有的迭代器。
除了直接检查所有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"
迭代器被定义为QList
中的QTreeModel
。
QList
是基于指数的。如果删除了具有当前索引的项目,则下一个项目将成为当前索引。
请参阅以下链接。您将看到迭代器的定义,如下所示。
https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qtreewidget_p.h.html#QTreeModel
你会看到这样的定义
QList<QTreeWidgetItemIterator*> iterators;
现在,当你在迭代器上调用delete时,会调用QTreeWidgetItemIterator
的析构函数。
QTreeWidgetItemIterator::~QTreeWidgetItemIterator()
{
d_func()->m_model->iterators.removeAll(this);
}
通过注意上面的代码,使用QList
函数removeAll
删除迭代器,并从列表中完全删除迭代器。
QList
是基于指数的。因此,如果删除具有索引3的迭代器,则下一个迭代器索引将变为3。
现在当你做++时,
调用下面的函数,它会带来列表中的下一个项目。所以你将迭代器移动到下一个项目(索引4)。
QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator++()
{
if (current)
do {
current = d_func()->next(current);
} while (current && !matchesFlags(current));
return *this;
}
该模型的QTreeWidgetItemIterator
维持为QList
。因此,当您删除迭代器时,下一个迭代器将成为当前索引。所以你确实注意到了这种行为。