56

C ++forループとforeachQtが提供する演算子のどちらが優れているか(または高速か)?たとえば、次の条件

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
}
4

11 に答える 11

152

ほとんどの場合、それは本当に問題ではありません。

このメソッドまたはそのメソッドのどちらがより高速であるかに関する StackOverflow に関する多数の質問は、ほとんどの場合、コードはほとんどの時間をユーザーが何かを行うのを待って座っているという事実に反しています。

本当に心配な場合、自分でプロファイリングして、見つけたものに基づいて行動してください。

しかし、この問題が重要になるのは、最も集中的なデータ処理の重い作業でのみであることがわかると思います。その差はほんの数秒かもしれませんし、それでも膨大な数の要素を処理する場合に限られます。

最初にコードを機能させます。次に、高速に動作するようにします (実際のパフォーマンスの問題が見つかった場合のみ)。

機能を完成させて適切にプロファイリングできるようになるまでの最適化に費やす時間は、ほとんど無駄な時間です。

于 2009-04-21T04:19:41.613 に答える
25

まず最初に、私は Pax に同意し、速度はおそらくそれに含まれていないと言いたいと思います。foreach は可読性に基づいて決定的であり、98% のケースでは十分です。

しかしもちろん、Qt の人たちはそれを調べて、実際にいくつかのプロファイリングを行いました: http://blog.qt.io/blog/2009/01/23/iterating-effectively/

そこから得られる主な教訓は、一時的なインスタンスの作成を回避するため、読み取り専用ループで const 参照を使用することです。また、使用するループ方法に関係なく、ループの目的をより明確にします。

于 2009-04-21T16:07:52.800 に答える
19

それは本当に問題ではありません。プログラムが遅い場合、これは問題ではない可能性があります。ただし、完全に同等の比較を行うわけではないことに注意してください。Qtforeachはこれに似ています (この例では を使用しますQList<QString>)。

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

マクロは、いくつかのコンパイラ拡張機能 (GCC の など__typeof__) を使用して、渡されたコンテナーのタイプを取得することでこれを行うことができます。また、ブーストのBOOST_FOREACH概念は非常に似ていると想像してください。

あなたの例が公平ではない理由は、非 Qt バージョンが余分な作業を追加しているためです。

実際に反復するのではなく、インデックスを作成しています。非連続割り当ての型を使用している場合 (これは の場合であると思われますQList<>)、コードは n 番目の項目が「どこにあるのか」を計算する必要があるため、インデックス作成のコストが高くなります。

そうは言っても。それでも構いません。これら 2 つのコード間のタイミングの違いは、存在するとしても無視できます。心配して時間を無駄にしないでください。より明確で理解しやすいと思われる方を書きます。

編集:おまけとして、現在、私はコンテナー反復の C++11 バージョンを強く支持しています。これは、クリーンで簡潔でシンプルです。

for(QString &s : Con) {
    // you code here
}
于 2009-04-21T17:27:54.590 に答える
13

どちらが速いかという質問には答えたくありませんが、どちらが優れているかは言いたいです。

Qt の foreach の最大の問題は、反復処理の前にコンテナーのコピーを取得することです。「Qt クラスは refcounted であるため、これは問題ではありません」と言うことができますが、コピーが使用されるため、実際には元のコンテナーはまったく変更されません。

要約すると、Qt の foreach は読み取り専用ループにのみ使用できるため、避ける必要があります。Qt では、コンテナーを更新/変更すると思われる foreach ループを作成できますが、最終的にはすべての変更が破棄されます。

于 2009-04-25T14:13:37.100 に答える
4

まず、「どうでもいい」という回答に大賛成です。最もクリーンなソリューションを選択し、それが問題になる場合は最適化します。

しかし、別の見方をすれば、多くの場合、最速の解決策は、意図を最も正確に説明するものです。この場合、QT の foreach は、コンテナ内の各要素に何らかのアクションを適用したいと言っています。

普通の for ループは、 counter が欲しいと言いますi。この値 i に繰り返し 1 を追加し、それがコンテナー内の要素の数よりも少ない限り、何らかのアクションを実行したいとします。

言い換えれば、単純な for ループは問題を過剰に指定しています。実際にやろうとしていることの一部ではない多くの要件が追加されます。ループカウンターはにしません。しかし、for ループを作成するとすぐに、そこになければなりません。

一方、QT の人々は、パフォーマンスに影響を与える可能性のある追加の約束をしていません。それらは、コンテナーを反復処理し、それぞれにアクションを適用することを保証するだけです。

つまり、多くの場合、最もクリーンでエレガントなソリューションは最速でもあります。

于 2009-04-21T16:53:14.953 に答える
3

Qt の foreach は、for ループの IMHO の構文がより明確であるため、その意味では優れています。パフォーマンスに関しては、そこに何かがあるとは思えません。

代わりにBOOST_FOREACHを使用することを検討できます。これはよく考え抜かれたファンシーな for ループであり、移植可能です (おそらくいつか C++ に組み込まれ、将来的にも証明されるでしょう)。

于 2009-04-21T04:21:28.100 に答える
3

これに関するベンチマークとその結果は、http://richelbilderbeek.nl/CppExerciseAddOneAnswer.htmにあります。

私見(およびここにいる他の多くの人)それ(つまり速度)は問題ではありません。

しかし、自由に自分の結論を導き出してください。

于 2010-07-25T09:52:15.190 に答える
2

小さなコレクションの場合、それは重要であり、 foreach の方が明確になる傾向があります。

ただし、より大きなコレクションの場合、ある時点で for が foreach を打ち負かすようになります。(「at()」演算子が効率的であると仮定します。

これが本当に重要である場合(そして、あなたが尋ねているのでそうであると私は推測しています)、最善の方法はそれを測定することです. プロファイラーがそのトリックを行う必要があります。または、何らかのインストルメンテーションを使用してテスト バージョンをビルドすることもできます。

于 2009-04-21T04:26:10.833 に答える
0

You might look at the STL's for_each function. I don't know whether it will be faster than the two options you present, but it is more standardized than the Qt foreach and avoids some of the problems that you may run into with a regular for loop (namely out of bounds indexing and difficulties with translating the loop to a different data structure).

于 2009-04-21T15:09:01.333 に答える
0

foreach は、場合によっては名目上高速に動作することを期待しますが、項目が実際の配列である場合を除き、パフォーマンスの違いはごくわずかです。

列挙子の上に実装されている場合、実装によっては、単純なインデックス作成よりも効率的である可能性があります。効率が悪いということはまずありません。たとえば、バランスの取れたツリーをインデックス可能かつ列挙可能として公開した場合、 foreach はかなり高速になります。これは、各インデックスが参照されるアイテムを個別に見つける必要があるためです。一方、列挙子は現在のノードのコンテキストを持っており、次の ont に効率的に移動できます。

実際の配列がある場合、 foreach が for と同じ場合に高速になるかどうかは、言語とクラスの実装に依存します。

インデックス作成がリテラル メモリ オフセット (C++ など) である場合、関数呼び出しを回避しているため、 for はわずかに高速になるはずです。インデックス作成が呼び出しと同じように間接的である場合は、同じである必要があります。

そうは言っても...ここで一般化するケースを見つけるのは難しいと思います。これは、アプリケーションにパフォーマンスの問題がある場合でも、探すべき最後の種類の最適化です。反復方法を変更することで解決できるパフォーマンスの問題がある場合、実際にはパフォーマンスの問題はありません。誰かが本当にくだらないイテレータまたは本当にくだらないインデクサーを書いたので、バグがあります。

于 2009-04-21T04:50:07.483 に答える