(二十四)容器的遍历、隐式共享

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

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值