Qt中迭代分为两类
1、 只读迭代器:不能改写对待器指向的数据
2、 读写迭代器:可以更改迭代器指向的数据
Qt中Java风格的迭代器:
1、只读迭代器类:Q + “容器名” + Iterator,如QVectorIterator<T>为只读向量迭代器,其中QVectorIterator是模板类,并不是类型,需要指定信息说明实例化为什么类型QVectorIterator<T>
2、读写迭代器类: QMutable+ “容器名” + Iterator,如QMutableVectorIterator<T>
Java风格的迭代器指向位置:
Java风格的迭代器并不直接指向容器中的任何元素,而是指向第一个元素之前、两个元素间或者最后一个元素之后的位置
遍历:
当一个迭代器被构造之后,会默认的指向容器中第一个元素之前的位置,我们可以通过成员函数:
bool | hasNext () const |
与
const T & | next () |
相配合来进行从前向后的遍历,当迭代器后面有一个元素时,hasNext ()将会返回真,这种情况下使用next ()就可以返回后一个元素的引用并使迭代器指向下一个位置
QList<float> list;
...
QListIterator<float> i(list); //Java风格迭代器
while (i.hasNext())
qDebug() << i.next();
如果需要向前遍历,可以使用成员函数
void | toBack () |
bool | hasPrevious () const |
const T & | previous () |
相配合,先将迭代器指向最后一个元素之后的位置,当迭代器前面有一个元素时hasPrevious ()返回真,使用previous ()返回前一个元素的引用并使迭代器指向上一个位置,读写 迭代器与只读迭代器遍历方式一致
Qt中的STL风格迭代器:
1、只读迭代器:Class<T>::const_iterator 其中,Class指Qt中的容器模板类
2、读写迭代器:Class<T>::iterator
STL风格迭代器指向位置:
跟STL中的迭代器一样,Qt中容器模板类的成员函数
iterator | begin () |
const_iterator | begin () const |
返回的STL风格的迭代器指向容器中第一个元素,成员函数
iterator | end () |
const_iterator | end () const |
返回的STL风格的迭代器指向容器不存在的尾后元素(容器中最后一个元素后的不存在元素),可以通过begin ()与end ()的返回值是否一致来判定容器是否为空,容器也为我们提供了更方便的方法,使用成员函数
bool | isEmpty () const |
遍历:
可以通过自增++或自减—运算符使STL风格迭代器移动到下一个位置(下一个元素或尾后迭代器)
QList<QString> list;
list<< "A" << "B" << "C" <<"D";
QList<QString>::iterator i; //STL风格迭代器
for(i = list.begin(); i != list.end(); ++i)
*i = (*i).toLower();
注意:如果要使用STL风格的迭代器遍历某些函数返回的容器,我们应该先获得那个返回的容器的拷贝,再遍历这个拷贝
const QList<int> sizes = splitter->sizes(); //隐式共享(拷贝构造,引用计数+1,不发生深拷贝)
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>),而执行流到下一行的时候临时对象被摧毁
使用Java风格的迭代器时,无需先获取返回的容器的拷贝,由于隐式共享的关系,只要我们进行只读操作,将不会引发拷贝,当我们进行了写操作时Qt会自动为我们拷贝数据,我们无需做任何额外的操作。
使用Java风格的迭代器:
QListIterator<int>i(splitter->sizes()); //隐式共享(拷贝构造,引用计数+1,不发生深拷贝)
while (i.hasNext())
{
//doSomething(i.next());
}
隐式共享:
有了隐式共享我们可以写这样的代码而不用担心性能问题
//实现
QVector<double> sineTable()
{
QVector<double> vect(345,360);
//...
return vect;
}
// 调用
QVector<double> v = sineTable(); //隐式共享
如果没有隐式共享的话,实现的方式就应该变化了,就应该使用使用pass-by-reference的方式来避免返回时发生的拷贝,有了隐式共享我们甚至可以这样写:
QVector<double>& sineTable() //返回引用
{
QVector<double> vect(345, 360); //local对象
//...
return vect;
}
QVector<double> v = sineTable(); //隐式共享
这里我们返回了局部对象的引用!!!!!这在C++中是绝对不被建议的(有疑问可以参考”Effective C++” 条款21)
Qt中所有容器类以其类QByteArray,QBrush, QFont, QImage, QPixmap和QString都使用了隐式共享技术。
为了更好的发挥隐式共享的优势
1、在访问QList<T>与QVector<T>时,我们应该尽量避免使用
成员函数
const T & | at ( int i ) const |
而不是重载的数组操作符
T & | operator[] ( int i ) |
2、在使用STL风格的迭代器遍历容器类时,只要在非常量的容器类上调用begin ()或end (),并且如果数据是隐式共享的,Qt将会强制执行深层拷贝,我们应该使用const_iterator、
const_iterator | constBegin () const |
const_iterator | constEnd () const |