2021.6.1:QT——Qt迭代器(Java类型与STL类型)
迭代器为访问容器类中的数据提供了统一的方法,Qt有两种迭代器:Java类型的迭代器和STL类型的迭代器。
两者比较,Java迭代器更易于使用且提供了一些高级功能,而STL类型的迭代器效率更高。
Java类型迭代器
对每个容器类,有两个Java类型迭代器——一个用于只读操作,另一个用于读写操作,各个Java类型的容器类见下表
| 容器类 | 只读迭代器 | 读写迭代器 |
|---|---|---|
| QList<T>, QQueue<T> | QListIterator<T> | QMutableListIterator<T> |
| QLinkedList<T> | QLinkedListIterator<T> | QMutableLinkedListIterator<T> |
| QVector<T>, QStack<T> | QVectorllcrator<T> | QMutableVectorIterator<T> |
| QSet<T> | QSetIterator<T> | QMutableSetIterator<T> |
| QMap<Key, T>, QMultiMap<Key, T> | QMapIterator<Key, T> | QMutableMapIterator<Key, T> |
| QHash<Key, T>, QMultiHash<Key, T> | QHashIterator<Key, T> | QMutablcHashlterator<Key, T> |
QMap和QHash等关联容器类的迭代器用法相同,QList和QLinkedList、QSet等容器类的用法相同,所以下面只以QMap和QList为例介绍迭代器的用法。
顺序容器的迭代器——QList
Java类型迭代器的指针并不是指向单个数据项,而是在数据项之间,迭代器指针位置示意图如下图:

下面是遍历访问一个QList<QString>容器的所有数据项的典型代码:
QList<QString> list; list<<"A"<<"B"<<"C"<<"D"; QListIterator<QString>i (list); while (i.hasNext()) qDebug() << i.next();
QList<QString>容器对象list作为参数传递给QListIterator<QString>迭代器i的构造函数,i用于对list作只读遍历。起始时刻,迭代器指针在容器第一个数据项之前(即上图的“A”之前),调用hasNext()判断在迭代器指针后面是否还有数据项,如果有,就调用next()跳过一个数据项,并且next()函数返回跳过的数据项。
也可以反向遍历,示例代码如下:
QListIterator<QString> i (list); i.toBack(); while(i.hasPrevious()) qDebug() << i.previous();
QListIterator用于移动指针和读取数据的函数见下表:
| 函数名 | 功能 |
|---|---|
| void toFront() | 迭代器移动到列表的最前面(第一个数据项之前) |
| void toBack() | 迭代器移动到列表的最后面(最后一个数据项之后) |
| bool hasNext() | 如果迭代器不是位于列表最后位罝,返回true |
| const T& next() | 返回下一个数据项,并且迭代器后移一个位置 |
| const T& peekNext() | 返回下一个数据项,但是不移动迭代器位置 |
| bool hasPrevious() | 如果迭代器不是位于列表的最前面,返回true |
| const T& previous() | 返回前一个数据项,并且迭代器前移一个位置 |
| const T& peekPrevious() | 返回前一个数椐项,但是不移动迭代器指针 |
QListIterator是只读访问容器内数据项的迭代器,若要在遍历过程中对容器的数据进行修改,需要使用QMutableListIterator。例如下面的代码为删除容器中数据为奇数的项:
QList<int> list; list<<1<<2<<3<<4<<5; QMutableListIterator <int> i (list); while(i.hasNext()){ if(i.next()%2 != 0) i.remove(); }
remove()函数移除next()刚刚跳过的数据项,不会使迭代器失效。setValue()函数可以修改刚刚跳过去的数据项的值。
关联容器类的迭代器——QMap
对于关联容器类QMap<Key T>,使用QMapIterator和QMutableMapIterator迭代器类,它们具有上表所示的所有函数,只是增加了key()和value()函数用于获取刚刚跳过的数据项的键和值。
例如,下面的代码将删除Key中以"City"结尾的数据项:
QMap<QString,QString> map; map.insert("Paris", "France"); map.insert("New York", "USA"); map.insert("Mexico City", "USA"); map.insert("Moscow", "Russia"); ... QMutableMapIterator <QString,QString> i (map); while (i.hasNext()){ if(i.next().key().endsWith("City")) i.remove(); }
如果是在多值容器内遍历,可以用findNext()或findPrevious()查找下一个或者上一个值,如下面的代码将删除上文map中value为"USA"的所有数据项:
QMutableMapIterator<QString,QString> i(map); while(i.findNext("USA")) i.remove();
STL迭代器
STL迭代器与Qt和STL原生算法兼容,并且进行了速度优化。具体类型见下表:
| 容器类 | 只读迭代器 | 读写迭代器 |
|---|---|---|
| QList<T>, QQueue<T> | QList<T>::const_iterator | QList<T>::iterator |
| QLinkedList<T> | Q1. i nked List<1>: :const_iterator | QLinkedList<T>::iterator |
| QVector<T>, QStack<T> | QVector<T>::const_ilerator | QVector<T>::iterator |
| QSet<T> | QSet<T>::const_iterator | QSet<T>::iterator |
| QMap<Key, P> QMultiMap<Kcy, T> | QMap<Key, T>::const_iterator | QMap<Key, T>:: iterator |
| QHash<Key, T> QMultiHash<Key, T> | QHash<Key, T>: :const_iterator | QHash<Key, T>::iterator |
对每个容器类,同样也有两个STL迭代器——只读和读写。无需修改数据时一定使用只读迭代器,因为速度更快。
注意,两种迭代器在定义时,使用了不同的关键字,const_iterator定义只读迭代器,iterator定义读写迭代器。此外,还可以使用const_reverse_iterator和reverse_iterator定义相应的反向迭代器。
STL迭代器就是C++中的指针,所以"++"运算符使迭代器指向下一个数据项,运算符返回数据项内容。这就是与Java迭代器不同的地方,STL迭代器直接指向数据项

begin()函数使迭代器指向容器的第一个数据项,end()使迭代器指向最后一个数据项之后的空数据项,常用作迭代结束条件。
下面仍以QList和QMap为例说明STL迭代器的用法。
顺序容器迭代器——QList
下面的代码将QList<QString> list中的数据项逐项输出:
QList<QString>list; list<<"A"<<"B"<<"C"<<"D"; QList<QString>::const_iterator i; for (i=list.constBegin();i!=list.constEnd();i++) qDebug()<<*i;
constBegin()和constEnd()是用于只读迭代器的,表示起始和结束位置。
若使用反向迭代器,并将上面代码中的数据项都改为小写。代码如下:
QList<QString>::reverse_iterator i; for(i = list.rbegin();i!=list.rend();i++) *i=i->toLower();
关联容器迭代器——QMap
对于关联容器类QMap和QHash,迭代器的操作符返回数据项的Value。如果想返回Key,使用key()函数,对应的,用value()函数一个项的value。
例如,下面的代码将QMap<int,int>map中所有Key、Value输出:
QMap<int,int>map; ... QMap<int,int>::const_iterator i; for (i=map.constBegin();i!=map.constEnd();i++) qDebug()<<i.key()<<i.value();
Qt API包含很多返回值为QList或QStringList的函数,要遍历这些返回的容器,必须先复制。由于QT使用了隐式共享,所以这样的复制并无多大开销。
例如,下面的代码是正确的:
const QList<int> sizes = splitter->sizes(); QList<int>::const_iterator i; for(i=sizes.begin();i!=sizes.end();i++)
而下面的代码是错误的:
QList<int>::const_iterator i; for(i=splitter->sizes().begin();i!=splitter->sizes().end();i++)
说明:隐式共享是对象的管理方法。一个对象被隐式共享,只是传递该对象的指针给使用者,而不复制对象数据,只有在使用者修改数据时,才实质复制共享对象给使用者。例如上边的代码中,splitter->sizes()返回的是一个QList<int>M表对象sizes,但是实际上并不传递内容,只是传递给它一个指针,只有当sizes发生数据修改时,才会将数据复制给sizes,这样避免了不必要的复制,减少了资源占用。
对于STL迭代器,隐式共享还涉及另一个问题,当一个迭代器在操作一个容器变量时,不要去复制这个容器变量。
总结
- 迭代器是用于访问容器类中数据项的模板类;
- 有两种迭代器:Java和STL迭代器;Java迭代器中,指针指向数据项之间;STL迭代器中,指针指向数据项本身;
- Java迭代器:以QList<T>为例,它的迭代器有QListIterator<T>和QMutableListIterator<T>两种,分别是Read-Only和Read&Write,其中QListIterator<T>用法:
QList<QString> list; list<<"A"<<"B"<<"C"<<"D"; QListIterator<QString> i (list); while(i.hasNext()) qDebug()<<i.next();
构建迭代器类型时,将QList对象作为参数传递给迭代器i的构造函数,表示i是QList对象的迭代器,只能用于这个QList对象的迭代。
- 上段代码中,i.hasNext()判断指针i之后是否有数据项,i.next()跳过并返回跳过的数据项;此外,也有其它一些迭代方法,具体可在上文中查看;
- QMutableListIterator,读写迭代器,修改数据项的代码:
QList <int> list; list<<1<<2<<3<<4<<5; QMutableIterator <int> i (list); while(i.hasNext()) if(i.next()%2!=0) i.remove();
修改数据项的函数是setValue();
- QMap类的迭代:
QMap<QString,QString>map; ... QMutableMapIterator<QString,QString> i (map); while(i.hasNext()) if(i.next().key().endsWith("City")) i.remove();
- STL迭代器:以QList<T>为例,也有两种迭代器:QList<T>::const_iterator、QList<T>::iterator,同样也是Read-Only、Read&Write
- STL迭代器就是C++中的指针,指向容器中的一个个数据项,可以使用“++”指向下一个数据项。list.constBegin(),list.constEnd()分别是Read-Only迭代器中指向容器类开始、结束数据项的函数。不过constEnd()并不是指结束项,而是结束项之后的空项,常用于迭代结束条件。
- 读写迭代器中,list.rend()、list.rbegin()分别指向结束和开始;
- 以QList<T>为例:
QList<QString>list; list<<"A"<<"B"<<"C"<<"D"; QList<QString>::const_iterator i; for(i=list.constBegin();i!=list.constEnd();i++) qDebug()<<*i;
在初始化迭代器的时候,不需要用QList对象来作为它的构造函数的参数。
- 以QMap为例:
QMap<int,int>map; ... QMap<int,int>::const_iterator i; for (i=map.constBegin();i!=map.constEnd();i++) qDebug()<<i.key()<<i.value();
- Qt中有许多返回值是QList的函数,要迭代这些返回的容器,需要先对容器复制。Qt使用了隐式共享,所以这样的复制并没有太大开销。
- 隐式共享——传递对象时,只传递指针,而不传递内容;

浙公网安备 33010602011771号