QT 容器及遍歷

QT容器遍歷分為Java和STL遍歷

STL風(fēng)格遍歷器的語(yǔ)法類似于使用指針對(duì)數(shù)組的操作。我們可以使用++和--運(yùn)算符使遍歷器移動(dòng)到下一位置,遍歷器的返回值是指向這個(gè)元素的指針。例如QVector<T>的iterator返回值是 T *類型,而const_iterator返回值是 const T * 類型(數(shù)據(jù)為常量,返回值不能修改)。

一個(gè)典型的使用STL風(fēng)格遍歷器的代碼是:

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

對(duì)于某些返回容器的函數(shù)而言,如果需要使用STL風(fēng)格的遍歷器,我們需要建立一個(gè)返回值的拷貝,然后再使用遍歷器進(jìn)行遍歷。如下面的代碼所示:

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

在C++中,很多人都會(huì)說(shuō),要避免這么寫,因?yàn)樽詈笠粋€(gè)return語(yǔ)句會(huì)進(jìn)行臨時(shí)對(duì)象的拷貝工作。如果這個(gè)對(duì)象很大,這個(gè)操作會(huì)很昂貴。所以,資深的C++高手們都會(huì)有一個(gè)STL風(fēng)格的寫法:

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);

這種寫法通過傳入一個(gè)引用避免了拷貝工作。但是這種寫法就不那么自然了。而隱式數(shù)據(jù)共享的使用讓我們能夠放心的按照第一種寫法書寫,而不必?fù)?dān)心性能問題。

Qt所有容器類以及其他一些類都使用了隱式數(shù)據(jù)共享技術(shù),這些類包括QByteArray, QBrush, QFont, QImage, QPixmap和QString。這使得這些類在參數(shù)和返回值中使用傳值方式相當(dāng)高效。

不過,為了正確使用隱式數(shù)據(jù)共享,我們需要建立一個(gè)良好的編程習(xí)慣。這其中之一就是,對(duì)list或者vector使用at()函數(shù)而不是[]操作符進(jìn)行只讀訪問。原因是[]操作符既可以是左值又可以是右值,這讓Qt容器很難判斷到底是左值還是右值,而at()函數(shù)是不能作為左值的,因此可以進(jìn)行隱式數(shù)據(jù)共享。另外一點(diǎn)是,對(duì)于begin(),end()以及其他一些非const容器,在數(shù)據(jù)改變時(shí)Qt會(huì)進(jìn)行深復(fù)制。為了避免這一點(diǎn),要盡可能使用const_iterator, constBegin()和constEnd().

最后,Qt提供了一種不使用遍歷器進(jìn)行遍歷的方法:foreach循環(huán)。這實(shí)際上是一個(gè)宏,使用代碼如下所示:

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

Qt容器類之關(guān)聯(lián)存儲(chǔ)容器

Qt提供兩種關(guān)聯(lián)容器類型:QMap<K, T>和QHash<K, T>。

QMap<K, T>是一種鍵-值對(duì)的數(shù)據(jù)結(jié)構(gòu),它實(shí)際上使用跳表skip-list實(shí)現(xiàn),按照K進(jìn)行升序的方式進(jìn)行存儲(chǔ)。使用QMap<K, T>的insert()函數(shù)可以向QMap<K, T>中插入數(shù)據(jù),典型的代碼如下:

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

同樣,QMap<K, T>也重載了[]運(yùn)算符,你可以按照數(shù)組的復(fù)制方式進(jìn)行使用:

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

遍歷關(guān)聯(lián)存儲(chǔ)容器的最簡(jiǎn)單的辦法是使用Java風(fēng)格的遍歷器。因?yàn)?code>Java風(fēng)格的遍歷器的next()和previous()函數(shù)可以返回一個(gè)鍵-值對(duì),而不僅僅是值,例如:

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

如果我們并不需要訪問鍵-值對(duì),可以直接忽略next()和previous()函數(shù)的返回值,而是調(diào)用key()和value()函數(shù)即可,如:

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

Mutable遍歷器則可以修改key對(duì)應(yīng)的值:

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

如果是STL風(fēng)格的遍歷器,則可以使用它的key()和value()函數(shù)。而對(duì)于foreach循環(huán),我們就需要分別對(duì)key和value進(jìn)行循環(huán)了:

QMultiMap<QString, int> map; 
... 
foreach (QString key, map.keys()) { 
       foreach (int value, map.values(key)) { 
               doSomething(key, value); 
       } 
} 
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容