STL ライブラリでは、いくつかのコンテナーにイテレーターがあり、単純な for ループよりも、これらのコンテナーを反復処理する優れた方法であると一般的に考えられています。
for ( int i=0; i < vecVector.size(); i++ )
{
..
}
なぜ、どのような場合にイテレータを使用する必要があるのか 、どのような場合に上記のコードスニペットを教えてもらえますか?
vector の通常の実装では、インデックス/サイズの型として「int」を使用しないことに注意してください。したがって、コードは少なくともコンパイラの警告を引き起こします。
イテレータは、コードの汎用性を高めます。
例えば:
typedef std::vector<int> Container ;
void doSomething(Container & p_aC)
{
for(Container::iterator it = p_aC.begin(), itEnd = p_aC.end(); it != itEnd; ++it)
{
int & i = *it ; // i is now a reference to the value iterated
// do something with "i"
}
}
ここで、ベクトルをリストに変更したとします (あなたの場合、リストの方が優れているため)。typedef 宣言を変更して、コードを再コンパイルするだけです。
代わりにインデックス ベースのコードを使用していた場合は、書き直す必要がありました。
イテレータは、一種のスーパー ポインターのように表示する必要があります。値 (または、マップの場合はキーと値のペア) を「指します」。
ただし、コンテナ内の次のアイテムに移動するメソッドがあります。または前の。一部のコンテナーでは、ランダム アクセスも提供されます (ベクターと両端キュー)。
ほとんどの STL アルゴリズムは、イテレータまたはイテレータの範囲で動作します (これも汎用性のためです)。ここでは、インデックスを使用できません。
イテレータを使用すると、コンテナの実装に依存しないコードを作成できます。コンテナへのランダム アクセスが安価であれば、パフォーマンス面で大きな違いはありません。
しかし、多くの場合、それが事実であるかどうかはわかりません。たとえば、添え字を使用して、リンクされたリストでメソッドを使用しようとすると、コンテナーは要素を見つけるために反復ごとにリストをたどる必要があります。
したがって、コンテナーへのランダム アクセスが安価であることが確実にわかっている場合を除き、反復子を使用してください。
関数への引数としてイテレータを使用する場合、使用される「コンテナ」のタイプからイテレータを切り離すことができます。たとえば、関数の結果をベクトルではなくコンソール出力に送信する場合があります (以下の例)。このトリックは、クラス間の結合を減らすのに非常に強力です。疎結合クラスはテストがはるかに簡単です。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template <typename InputIterator, typename OutputIterator>
void AddOne(InputIterator begin, InputIterator end, OutputIterator dest)
{
while (begin != end)
{
*dest = *begin + 1;
++dest;
++begin;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
vector<int> data;
data.push_back(1);
data.push_back(2);
data.push_back(3);
// Compute intermediate results vector and dump to console
vector<int> results;
AddOne(data.begin(), data.end(), back_inserter(results));
copy(results.begin(), results.end(), ostream_iterator<int>(cout, " "));
cout << endl;
// Compute results and send directly to console, no intermediate vector required
AddOne(data.begin(), data.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
あなたの例では、 vecVector. size() への呼び出しは、反復子を使用するよりも効率的ではありません。イテレータは基本的に、反復されるコンテナのサイズについて心配する必要がないようにカプセル化します。さらに、反復子は必ずしも順番通りに実行する必要はありません。適切と思われる方法で .next 呼び出しに応答する必要があります。
イテレータは、ほとんどがより高いレベルの抽象化です。
あなたのスニペットは、コンテナがインデックス化できることを前提としています。std::vector<>
これは、raw 配列などの他のコンテナにも当てはまります。
しかしstd::set<>
、インデックス作成が完全に欠けており、のインデックス演算子は、渡さstd::map<>
れた引数をマップに挿入します - ループで期待される動作ではありませんfor
。
また、パフォーマンスの問題は、測定されて証明された場合にのみ問題になります。
1 つには、そのベクトルをリストに変換すると、上記は機能しなくなります。
イテレータを使用すると、対象となるコンテナのタイプを知る必要のない関数テンプレートを作成できます。次のこともできます。
#include <algorithm>
void printvalue(double s)
{
// Do something with s
}
int _tmain(int argc, _TCHAR* argv[])
{
double s[20] = {0};
std::for_each(s, s+20, printvalue);
return 0;
}
これは、標準ポインターが for_each の有効な反復子でもあるためです。
デイブ