| 
 | 
	
沙发
 
 
 楼主 |
发表于 2017-1-22 14:56:20
|
只看该作者
 
 
 
 本帖最后由 Qter 于 2017-1-22 15:03 编辑  
 
遍历容器 
Qt 的容器类提供了两种风格的遍历器:Java 风格和 STL 风格。这两种风格的遍历器在通过非 const 函数对集合进行修改时都是不可用的。 
  Java 风格的遍历器 
  Java 风格的遍历器是在 Qt4 首先引入的,是 Qt 应用程序首先推荐使用的形式。这种风格比起 STL 风格的遍历器更方便。方便的代价就是不如后者高效。它们的 API 非常类似于 Java 的遍历器类,故名。 
  每一种容器都有两种 Java 风格的遍历器:一种提供只读访问,一种提供读写访问: 
 
 
 
| 容器 | 只读遍历器 | 读写遍历器 |  | QList,QQueue | QListIterator | QMutableListIterator |  | QLinkedList | QLinkedListIterator | QMutableLinkedListIterator |  | QVector,QStack | QVectorIterator | QMutableVectorIterator |  | QSet | QSetIterator | QMutableSetIterator |  | QMap,QMultiMap | QMapIterator | QMutableMapIterator |  | QHash,QMultiHash | QHashIterator | QMutableHashIterator |  
  
 
 
不同于下面我们将要介绍的 STL 风格的遍历器,Java 风格的遍历器指向的是两个元素之间的位置,而不是指向元素本身。因此,它们可能会指向集合第一个元素之前的位置,也可能指向集合的最后一个元素之后的位置。 
  我们通过调用hasNext()函数判断遍历器之后的位置上有无元素。如果有,调用next()函数将遍历器跳过其后的元素。next()函数返回刚刚跳过的元素。当然,我们也可以使用hasPrevious()和previous()函数来从尾部开始遍历,详细内容可以参考 API 文档。 
  QListIterator是只读遍历器,不能插入或者删除数据。如果需要这些操作,我们可以使用QMutableListIterator。 
  STL 风格的遍历器 
  STL 风格的遍历器从 Qt 2.0 就开始提供。这种遍历器能够兼容 Qt 和 STL 的通用算法,并且为速度进行了优化。同 Java 风格遍历器类似,Qt 也提供了两种 STL 风格的遍历器:一种是只读访问,一种是读写访问。我们推荐尽可能使用只读访问,因为它们要比读写访问的遍历器快一些。 
 
 
| 容器 | 只读遍历器 | 读写遍历器 |  | QList,QQueue | QList::const_iterator | QList::iterator |  | QLinkedList | QLinkedList::const_iterator | QLinkedList::iterator |  | QVector,QStack | QVector::const_iterator | QVector::iterator |  | QSet | QSet::const_iterator | QSet::iterator |  | QMap,QMultiMap | QMap::const_iterator | QMap::iterator |  | QHash,QMultiHash | QHash::const_iterator | QHash::iterator |  
  
 
STL 风格的遍历器具有类似数组指针的行为。例如,我们可以使用 ++ 运算符让遍历器移动到下一个元素,使用 运算符获取遍历器所指的元素。对于QVector和QStack,虽然它们是在连续内存区存储元素,遍历器类型是`typedef T ,const_iterator类型则是typedef const T *`。 
  不同于 Java 风格遍历器,STL 风格遍历器直接指向元素本身。容器的begin()函数返回指向该容器第一个元素的遍历器;end()函数返回指向该容器最后一个元素之后的元素的遍历器。end()实际是一个非法位置,永远不可达。这是为跳出循环做的一个虚元素。如果集合是空的,begin()等于end(),我们就不能执行循环。 
  由于有隐式数据共享(我们会在后面的章节介绍该部分内容),即使一个函数返回集合中元素的值也不会有很大的代价。Qt API 包含了很多以值的形式返回QList或QStringList的函数(例如QSplitter::sizes())。如果你希望使用 STL 风格的遍历器遍历这样的元素,应该使用容器的拷贝,例如: 
 
 
 
- // 正确的方式
 
 - const QList<QString> sizes = splitter->sizes();
 
 - QList<QString>::const_iterator i;
 
 - for (i = sizes.begin(); i != sizes.end(); ++i)
 
 -     ...
 
 - // 错误的方式
 
 - QList<QString>::const_iterator i;
 
 - for (i = splitter->sizes().begin();
 
 -      i != splitter->sizes().end(); ++i)
 
 -     ...
 
  复制代码 这个问题不存在于那些返回集合的 const 或非 const 引用的函数。隐式数据共享对 STL 风格遍历器造成的另外影响是,在容器上运行着非 const 遍历器的时候,不能对容器进行拷贝。Java 风格的遍历器没有这个问题。 
  foreach关键字 
  如果类型名中带有逗号,比如QPair,我们只能像上面一样,先创建一个对象,然后使用foreach关键字。如果没有逗号,则可以直接在foreach关键字中使用新的对象。 
  Qt 会在foreach循环时自动拷贝容器。这意味着,如果在遍历时修改集合,对于正在进行的遍历是没有影响的。即使不修改容器,拷贝也是会发生的。但是由于存在隐式数据共享,这种拷贝还是非常迅速的。 
  因为foreach创建了集合的拷贝,使用集合的非 const 引用也不能实际修改原始集合,所修改的只是这个拷贝。 
 
 
 |   
 
 
 
 |