日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

foreach、qAsConst用法总结

發(fā)布時間:2023/12/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 foreach、qAsConst用法总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

預備知識

本文要用到Qt的detach、隱式共享技術(shù),如果對這兩種技術(shù)不了解的讀者,請在qt官方自帶的Assistant 中的“索引”tab頁的搜索框中輸入implicitly shared,就可以看到Qt官方的闡述。

foreach說明

foreach關(guān)鍵字是Qt中用于遍歷容器的一個關(guān)鍵字,是Qt官方自己實現(xiàn)的,其不是C++標準中存在的關(guān)鍵字。其語法如下:

foreach (variable, container)

利用foreach可以對Qt自己的容器如:QVector、QMap、 QHash、QLinkedList、QList進行遍歷,如下:

QLinkedList<QString> list;...foreach (const QString &str, list) {if (str.isEmpty())break;qDebug() << str;}

對于QMap、 QHash鍵值對類型遍歷如下:

QMap<int, QString> mpStudent;mpStudent[0] = "dan";mpStudent[1] = "shi";mpStudent[2] = "ming";foreach(auto var, mpStudent){qDebug() << var<< "\r\n";}

結(jié)果如下:

可以看到,將foreach運用于QMap、QHash遍歷時,默認返回QMap、QHash鍵值對的值部分。如果要遍歷QMap、QHash的鍵部分,可將foreach語句改為如下:

foreach(auto var, mpStudent.keys())

如果要遍歷鍵又要遍歷值,則請用迭代器。

foreach也可以遍歷STL的容器,如下:

vector<int>vtSTLTest;for (auto i = 0; i < 10; ++i){vtSTLTest.push_back(i);}foreach(auto var, vtSTLTest){qDebug() << var << "\r\n";}

Qt進入到foreach循環(huán)后,會將容器自動拷貝一份,因為Qt的容器都是隱式共享的(類似于智能指針),所以拷貝Qt自己的容器過程非常快,幾乎對性能沒啥大的影響,但因為STL的容器沒有像Qt自己的容器那樣實現(xiàn)隱式共享,所以如果拷貝的是STL容器,有時代價是昂貴的。因為foreach自動拷貝了原來的容器,所以在foreach循環(huán)內(nèi),對容器的更改只會影響到拷貝的容器,對于原始容器則不會有影響,基于這一點,在foreach語法中,variable不能為非常量的引用,只能為值傳遞或常量引用,否則就可以對原始容器進行更改了,因此下面的語法,編譯器都會報錯

vector<int>vtSTLTest;for (auto i = 0; i < 10; ++i){vtSTLTest.push_back(i);}foreach(auto& var, vtSTLTest){var[1] = 2;qDebug() << var << "\r\n";}

??試圖修改原始容器索引為1的元素,會報錯

vector<int>vtSTLTest;for (auto i = 0; i < 10; ++i){vtSTLTest.push_back(i);}foreach(int& var, vtSTLTest){qDebug() << var << "\r\n";}

?非常量的int引用會導致原始容器被修改,所以會報錯。

foreach(int& var, vtSTLTest)

將上面一句代碼改為:

foreach(const int& var, vtSTLTest)

或改為:

foreach(int var, vtSTLTest)

不會報錯,這種情況下,不會導致對原始容器更改。

如果在用foreach遍歷容器時,外部更改了原始容器,則它不會影響foreach循環(huán),即foreach循環(huán)輸出的依然是原始容器未修改的值,這證明foreach確實復制了原始容器,操作的是復制容器而不是原始容器。如下:

#include "QtWidgetsApplication2.h" #include <QVector> #include <map> #include <thread> using namespace std;void fun(QVector<int>& vtQTest) {for (auto i = 0; i < 10; ++i){vtQTest[i] = i+2;} }QtWidgetsApplication2::QtWidgetsApplication2(QWidget *parent): QWidget(parent) {ui.setupUi(this);QVector<int>vtQTest;for (auto i = 0; i < 10; ++i){vtQTest.push_back(i);}std::thread* p{nullptr};foreach ( int var ,vtQTest){if (nullptr == p){p = new std::thread(fun, std::ref(vtQTest));// 等待5秒,以便原始容器內(nèi)的值能被線程全部更改完std::this_thread::sleep_for(std::chrono::milliseconds(5000)); }// 雖然上面線程修改了原始容器,但這里依然輸出的是未修改的值qDebug() << var << "\r\n";}foreach(int var, vtQTest) {// 進入到這個foreach,會重新拷貝一份vtQTest,而vtQTest在上面的線程中// 被更改了,所以這里輸出的更改后的值。qDebug() << "new :" << var << "\r\n";}}

輸出如下:

?

基于范圍的循環(huán)可能導致Qt庫容器會執(zhí)行detach操作,如下:

QString s = ...;for (QChar ch : s) // detaches 's' (performs a deep-copy if 's' was shared)process(ch);

上述代碼是用for實現(xiàn)的基于范圍的循環(huán),符合C++11標準語法。當process函數(shù)對ch進行更改操作之前,s就會被detach,之后再深拷貝出一個和s一樣的對象,而有時候我們不想被detach和深拷貝。但換成如下的foreach,則s不會被detach,僅僅進行指針級的淺拷貝:

QString s = ...;foreach (QChar ch, s) process(ch);

但是在STL的容器上用foreach,卻會導致復制操作,前文已經(jīng)說過,STL的容器沒有實現(xiàn)隱式共享,這有時會導致復制的代價很高,對性能和效率有影響。為了兼顧這兩者,Qt官方給出了如下建議:

  • 對于Qt自己實現(xiàn)的容器,如:QVector、QMap、 QHash、QLinkedList、QList等,建議用foreach進行循環(huán)。
  • 對于STL的容器,建議用for(var : container)基于范圍的循環(huán)。

qAsConst?

? ?自Qt 5.7版本以來,引入了qAsConst函數(shù),該函數(shù)Qt官方的解釋如下:

  • This function is a Qt implementation of C++17's std::as_const(),this function turns non-const lvalues into const lvalues
  • Added qAsConst function to help using non-const Qt containers in C++11 range for loops
  • Its main use in Qt is to prevent implicitly-shared Qt containers from detaching

意思就是說:

  • 這個函數(shù)實現(xiàn)了C++17標準中的std::as_const()函數(shù)的功能,將一個非常量的左值轉(zhuǎn)為常量的左值。
  • 增加qAsConst函數(shù)是為了Qt自己的容器能實現(xiàn)C++11標準的基于范圍的循環(huán)。
  • 該函數(shù)主要用于qt容器在隱式共享中不被detach。

從上文的描述,我們知道下面的代碼:

QString s = ...;for (QChar ch : s) // detaches 's' (performs a deep-copy if 's' was shared)process(ch);

將會導致s被detach,繼而再執(zhí)行深拷貝,而下面的代碼s不會被detach,當然也就不會再執(zhí)行深拷貝了

for (QChar ch : qAsConst(s)) // ok, no detach attemptprocess(ch);

當然,在這種情況下,你也許會說,像下面那樣將s聲明為const,也不會執(zhí)被detach:

const QString s = ...;for (QChar ch : s) // ok, no detach attempt on const objectsprocess(ch);

但是在編程時、在現(xiàn)實中,聲明為const往往不容易做到。

總結(jié):對Qt自己實現(xiàn)的容器如:QVector、QMap、 QHash、QLinkedList、QList等,如果一定要用基于for(var : container)范圍的循環(huán),則請用如下形式:

for(var : qAsConst(container))

總結(jié)

以上是生活随笔為你收集整理的foreach、qAsConst用法总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。