QT 容器及遍历

2017-04-09  本文已影响0人  YBshone

QT容器遍历分为Java和STL遍历

STL风格遍历器的语法类似于使用指针对数组的操作。我们可以使用++和--运算符使遍历器移动到下一位置,遍历器的返回值是指向这个元素的指针。例如QVector<T>的iterator返回值是 T *类型,而const_iterator返回值是 const T * 类型(数据为常量,返回值不能修改)。

一个典型的使用STL风格遍历器的代码是:

QList<double>::iterator i = list.begin(); 
while (i != list.end()) { 
       *i = qAbs(*i); 
       ++i; 
}

对于某些返回容器的函数而言,如果需要使用STL风格的遍历器,我们需要建立一个返回值的拷贝,然后再使用遍历器进行遍历。如下面的代码所示:

QList<int> list = splitter->sizes(); 
QList<int>::const_iterator i = list.begin(); 
while (i != list.end()) { 
        doSomething(*i); 
        ++i; 
}

在C++中,很多人都会说,要避免这么写,因为最后一个return语句会进行临时对象的拷贝工作。如果这个对象很大,这个操作会很昂贵。所以,资深的C++高手们都会有一个STL风格的写法:

void sineTable(std::vector<double> &vect)    
{    
                vect.resize(360);    
                for (int i = 0; i < 360; ++i)    
                                vect[i] = std::sin(i / (2 * M_PI));    
} 
// call 
QVector<double> v; 
sineTable(v);

这种写法通过传入一个引用避免了拷贝工作。但是这种写法就不那么自然了。而隐式数据共享的使用让我们能够放心的按照第一种写法书写,而不必担心性能问题。

Qt所有容器类以及其他一些类都使用了隐式数据共享技术,这些类包括QByteArray, QBrush, QFont, QImage, QPixmap和QString。这使得这些类在参数和返回值中使用传值方式相当高效。

不过,为了正确使用隐式数据共享,我们需要建立一个良好的编程习惯。这其中之一就是,对list或者vector使用at()函数而不是[]操作符进行只读访问。原因是[]操作符既可以是左值又可以是右值,这让Qt容器很难判断到底是左值还是右值,而at()函数是不能作为左值的,因此可以进行隐式数据共享。另外一点是,对于begin(),end()以及其他一些非const容器,在数据改变时Qt会进行深复制。为了避免这一点,要尽可能使用const_iterator, constBegin()和constEnd().

最后,Qt提供了一种不使用遍历器进行遍历的方法:foreach循环。这实际上是一个宏,使用代码如下所示:

QLinkedList<Movie> list; 
Movie movie; 
... 
foreach (movie, list) { 
       if (movie.title() == "Citizen Kane") { 
               std::cout << "Found Citizen Kane" << std::endl; 
               break; 
       } 
}

Qt容器类之关联存储容器

Qt提供两种关联容器类型:QMap<K, T>和QHash<K, T>。

QMap<K, T>是一种键-值对的数据结构,它实际上使用跳表skip-list实现,按照K进行升序的方式进行存储。使用QMap<K, T>的insert()函数可以向QMap<K, T>中插入数据,典型的代码如下:

QMap<QString, int> map; 
map.insert("eins", 1); 
map.insert("sieben", 7); 
map.insert("dreiundzwanzig", 23);

同样,QMap<K, T>也重载了[]运算符,你可以按照数组的复制方式进行使用:

map["eins"] = 1; 
map["sieben"] = 7; 
map["dreiundzwanzig"] = 23;
int val = map.value("dreiundzwanzig");

遍历关联存储容器的最简单的办法是使用Java风格的遍历器。因为Java风格的遍历器的next()和previous()函数可以返回一个键-值对,而不仅仅是值,例如:

QMap<QString, int> map; 
... 
int sum = 0; 
QMapIterator<QString, int> i(map); 
while (i.hasNext()) 
       sum += i.next().value();

如果我们并不需要访问键-值对,可以直接忽略next()和previous()函数的返回值,而是调用key()和value()函数即可,如:

QMapIterator<QString, int> i(map); 
while (i.hasNext()) { 
       i.next(); 
       if (i.value() > largestValue) { 
               largestKey = i.key(); 
               largestValue = i.value(); 
       } 
}

Mutable遍历器则可以修改key对应的值:

QMutableMapIterator<QString, int> i(map); 
while (i.hasNext()) { 
       i.next(); 
       if (i.value() < 0.0) 
               i.setValue(-i.value()); 
}

如果是STL风格的遍历器,则可以使用它的key()和value()函数。而对于foreach循环,我们就需要分别对key和value进行循环了:

QMultiMap<QString, int> map; 
... 
foreach (QString key, map.keys()) { 
       foreach (int value, map.values(key)) { 
               doSomething(key, value); 
       } 
} 
上一篇下一篇

猜你喜欢

热点阅读