簡體   English   中英

'for'循環vs Qt的'foreach'在C ++中

[英]'for' loop vs Qt's 'foreach' in C++

哪個更好(或更快),一個C ++ for循環或Qt提供的foreach運算符? 例如,以下條件

QList<QString> listofstrings;

哪個更好?

foreach(QString str, listofstrings)
{
    //code
}

要么

int count = listofstrings.count();
QString str = QString();
for(int i=0;i<count;i++)
{
    str = listofstrings.at(i);
    //Code
}

在大多數情況下,這無關緊要。

關於這種方法或該方法是否更快的StackOverflow上的大量問題,認為在絕大多數情況下,代碼花費大部分時間等待用戶做某事。

如果你真的關心,簡介為自己和作用於你的發現。

但我認為你很可能會發現,只有在最激烈的數據處理工作中,這個問題才能解決。 只有在處理大量元素時,差異可能只有幾秒甚至更長時間。

讓代碼先運行 然后讓它快速運行 (並且只有在您發現實際性能問題時)。

在完成功能之前花費時間進行優化並且可以正確分析,這主要是浪費時間。

首先,我只想說我同意Pax,並且速度可能不會進入它。 foreach基於可讀性贏得了勝利,這在98%的情況下都足夠了。

但是當然Qt的人已經調查了它並且實際上做了一些分析: http//blog.qt.io/blog/2009/01/23/iterating-efficiently/

從中學到的主要教訓是:在只讀循環中使用const引用,因為它避免了臨時實例的創建。 無論您使用何種循環方法,它還使循環的目的更明確。

這沒關系 可能的情況是你的程序很慢,這不是問題。 但是,應該注意的是,你並沒有做出完全相同的比較。 Qt的foreach更類似於此(此示例將使用QList<QString> ):

for(QList<QString>::iterator it = Con.begin(); it != Con.end(); ++it) {
    QString &str = *it;
    // your code here
}

宏可以通過使用一些編譯器擴展(如GCC的__typeof__ )來獲取傳遞的容器類型。 還想象一下boost的BOOST_FOREACH在概念上非常相似。

你的例子不公平的原因是你的非Qt版本正在增加額外的工作。

您正在編制索引而不是實際迭代。 如果您使用的是具有非連續分配的類型(我懷疑這可能是QList<>的情況),那么索引將更加昂貴,因為代碼必須計算第n個項目的“where”。

話雖如此。 仍然沒關系。 如果存在的話,這兩段代碼之間的時間差異可以忽略不計。 不要浪費你的時間擔心它。 寫下你發現的更清晰易懂的內容。

編輯:作為獎勵,目前我非常支持C ++ 11版本的容器迭代,它簡潔明了:

for(QString &s : Con) {
    // you code here
}

我不想回答更快的問題,但我想說哪個更好。

Qt的foreach最大的問題是它在迭代之前需要一個容器的副本。 您可以說'這無關緊要,因為Qt類已被重新計算',但由於使用了副本,您根本不會實際更改原始容器。

總之,Qt的foreach只能用於只讀循環,因此應該避免使用。 Qt很樂意讓你編寫一個foreach循環,你認為它會更新/修改你的容器,但最后所有的變化都會被拋棄。

由於Qt的5.7 foreach宏已被棄用,QT鼓勵您使用C ++ 11 for替代。
http://doc.qt.io/qt-5/qtglobal.html#foreach

(有關差異的更多詳細信息,請訪問: https//www.kdab.com/goodbye-q_foreach/

首先,我完全贊同“無所謂”的答案。 選擇最干凈的解決方案,並優化是否成為問題。

但另一種看待它的方法是,最快的解決方案通常是最准確地描述您的意圖的解決方案。 在這種情況下,QT的foreach表示您希望對容器中的每個元素應用一些操作。

一個普通的循環說你想要一個反擊i 您希望重復向此值i添加一個,並且只要它小於容器中的元素數,您就可以執行某些操作。

換句話說,plain for循環過度指定了問題。 它增加了許多要求,而這些要求實際上並不是您要做的事情的一部分。 你不關心循環計數器。 但是只要你編寫一個for循環,就必須在那里。

另一方面,QT人員沒有做出可能影響績效的額外承諾。 它們只是保證迭代容器並對每個容器應用一個動作。

換句話說,通常最干凈,最優雅的解決方案也是最快的。

關於此的基准及其結果可以在http://richelbilderbeek.nl/CppExerciseAddOneAnswer.htm找到。

恕我直言(以及其他許多人)它(即速度)並不重要。

但請隨意得出自己的結論。

來自Qt的foreach有一個更清晰的for循環恕我直言的語法,所以在這個意義上它更好。 表現明智我懷疑它有什么。

您可以考慮使用BOOST_FOREACH ,因為它是一個經過深思熟慮的循環,並且它是可移植的(並且可能會讓它在某天進入C ++並且也是未來的證明)。

對於小型館藏來說,它應該是重要的,而且預期往往更清晰。

然而,對於較大的收藏品,將在某些時候開始擊敗foreach。 (假設'at()'運算符是有效的。

如果這非常重要(我假設它是你要求的那樣),那么最好的辦法就是衡量它。 分析器應該可以解決問題,或者您可以使用一些檢測來構建測試版本。

我希望foreach在某些情況下名義上更快,而在其他情況下大致相同,除非項目是實際數組,在這種情況下,性能差異可以忽略不計。

如果它是在枚舉器之上實現的,則它可能比直接索引更有效,具體取決於實現。 它不太可能效率低下。 例如,如果有人將平衡樹暴露為可索引和可​​枚舉的,那么foreach將會更加快速。 這是因為每個索引必須獨立地找到引用的項,而枚舉器具有當前節點的上下文以更有效地導航到下一個ont。

如果你有一個實際的數組,那么它取決於語言和類的實現是否foreach將更快與for。相同。

如果索引是一個文字內存偏移量(例如C ++),那么因為你要避免函數調用,所以應該稍微快一點。 如果索引是一個間接,就像一個調用,那么它應該是相同的。

所有這一切......我發現很難找到一個概括的案例。 這是您應該尋找的最后一種優化,即使您的應用程序存在性能問題。 如果您遇到可以通過更改迭代方式來解決的性能問題,那么您實際上並沒有遇到性能問題。 你有一個BUG,因為有人寫了一個非常糟糕的迭代器,或者一個非常糟糕的索引器。

您可以查看STL的for_each函數。 我不知道它是否會比你提出的兩個選項更快,但它比Qt foreach更標准化,並避免了你可能遇到的常規for循環的一些問題(即越界索引和困難)將循環轉換為不同的數據結構)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM