web-dev-qa-db-ja.com

「for」ループとC ++のQtの「foreach」

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
}
46
Ajay

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

StackOverflowでこのメソッドまたはそのメソッドが高速であるかどうかに関する多数の質問は、ほとんどの場合、コードがユーザーの何かを待つのに時間を費やしているという事実を信じています。

areが本当に気になる場合は、自分でプロファイルを作成し、見つけたものに基づいて行動してください。

しかし、この質問の問題は、データ処理が非常に激しい作業でのみ発生する可能性が高いと思います。違いはほんの数秒であり、それでも膨大な数の要素を処理する場合に限られます。

コードを機能させるfirst。次に、それを動作させますfast(実際のパフォーマンスの問題を見つけた場合のみ)。

機能を終了して適切にプロファイルを作成する前に最適化に費やした時間は、ほとんどが無駄な時間です。

149
paxdiablo

まず、Paxに同意し、おそらく速度がそれに入らないと言いたいだけです。 foreachは可読性に基づいて勝ち取り、98%のケースでこれで十分です。

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

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

22
Parker Coates

それは本当に重要ではありません。おそらく、プログラムが遅い場合、これは問題ではありません。ただし、完全に同等の比較を行うわけではないことに注意してください。 Qtのforeachはこれに似ています(この例では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
}
15
Evan Teran

速い質問には答えたくありませんが、どちらが良いかを言いたいです。

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

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

10
Ben

Qt 5.7foreachマクロは推奨されないため、Qtでは代わりにC++ 11 forを使用することをお勧めします。
http://doc.qt.io/qt-5/qtglobal.html#foreach

(違いの詳細はこちら: https://www.kdab.com/goodbye-q_foreach/

7
ymoreau

まず、「問題ではない」という答えに完全に同意します。最もクリーンなソリューションを選択し、それが問題になる場合は最適化します。

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

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

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

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

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

4
jalf

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

代わりに BOOST_FOREACH を使用することを検討することができます。これは、ループについてよく考えられており、移植性があるためです(そして、いつかC++に組み込まれ、将来の証明にもなります)。

3
justinhj

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

私見(そしてここの他の多くの)それ(つまり速度)は重要ではありません。

しかし、あなた自身の結論を引き出してください。

3
Bilderbikkel

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

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

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

2
Foredecker

Foreachは、アイテムが実際の配列である場合を除き、パフォーマンスの違いが無視できる場合を除いて、場合によっては名目上高速に動作することを期待します。

列挙子の上に実装されている場合、実装によっては、ストレートインデックスよりも効率的です。効率が低下することはほとんどありません。たとえば、誰かがバランスの取れたツリーをインデックス可能と列挙可能の両方として公開した場合、foreachはかなり高速になります。これは、各インデックスが参照されるアイテムを個別に見つける必要がある一方で、列挙子が次のontにより効率的にナビゲートするために現在のノードのコンテキストを持っているためです。

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

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

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

1
Darren Clark

STLの for_each 関数を見ることができます。あなたが提示する2つのオプションよりも高速かどうかはわかりませんが、Qt foreachよりも標準化されており、通常のforループで発生する可能性のある問題の一部を回避します(つまり、範囲外のインデックス付けと困難ループを別のデータ構造に変換します)。

0
Jason Baker