C++STLにおける反復器の紹介

5514 ワード

反復器
反復器は、コンテナ内のオブジェクトへのアクセス方法を提供し、コンテナ内のオブジェクトの範囲を定義します.反復器はポインタのようなものです.実際、C++のポインタも反復器です.しかし、反復器はポインタだけではないので、アドレス値を持っているとは思えません.たとえば、配列インデックスは、反復器とも考えられます.
反復器には様々な作成方法があります.プログラムは反復器を変数として作成することができます.STLコンテナクラスは、特定のタイプのデータを使用するために反復器を作成することができます.ポインタとして、*オペレータクラスを使用してデータを取得できる必要があります.++などの他の数学オペレータも使用できます.通常、++オペレータは、コンテナ内の次のオブジェクトにアクセスするために反復器をインクリメントするために使用されます.反復器が容器の最後の要素の後ろに達すると、反復器はpast-the-end値になります.past-the-end値ポインタを使用してオブジェクトにアクセスするのは、NULLまたは初期化されたポインタを使用するように不正です.
ヒント
STLは、別の反復器から1つの反復器に到達することを保証しない.たとえば、1つのセット内のオブジェクトをソートするときに、異なる構造で2つの反復器を指定すると、2番目の反復器が最初の反復器から到達できなくなり、プログラムは失敗することになります.これはSTLの柔軟性の代価です.STLは、検出の不条理な誤りを保証しない.
反復器のタイプ
STLデータ構造とアルゴリズムでは、5種類の反復器を使用できます.次の5つのタイプを簡単に説明します.
・Input iteratorsは、データへの読取り専用アクセスを提供する.
・Output iteratorsデータへの書き込み専用アクセスを提供
・Forward iteratorsは、読み書き操作を提供し、反復器を前進させることができる.
・Bidirectional iteratorsは、読み書き操作を提供し、前後に操作することができる.
・Random access iteratorsは、読み書き操作を提供し、データ内をランダムに移動することができる.
様々なSTL実装の詳細が異なるにもかかわらず、上記の反復器は継承関係の一種として想像することができる.この意味では、次の反復器は上の反復器から継承されます.この継承関係のため、Forward反復器をoutputまたはinput反復器として使用できます.同様に、アルゴリズムがbidirectional反復器を必要とする場合、このタイプとランダムアクセス反復器しか使用できません.
ポインタ反復器
次のウィジェットに示すように、ポインタも反復器です.このプログラムは、STLの主な特性を示しています.これは、独自のクラスタイプだけでなく、任意のCまたはC++タイプにも使用できます.Listing 1, iterdemo.cppは,ポインタを反復器としてSTLのfind()アルゴリズムに用いて通常の配列を探索する方法を示した.
表1.iterdemo.cpp
#include 
#include 
using namespace std;
#define SIZE 100
int iarray[SIZE];
int main()
{
  iarray[20] = 50;
  int* ip = find(iarray, iarray + SIZE, 50);
  if (ip == iarray + SIZE)
  cout << "50 not found in array" << endl;
  else
  cout << *ip << " found in array" << endl;
  return 0;
}

I/OストリームライブラリとSTLアルゴリズムヘッダファイル(.h接尾辞がないことに注意)を参照して、このプログラムはコンパイラにstd名前空間を使用することを教えます.std名前空間を使用するこの行はオプションです.このようなウィジェットでは名前の競合は発生しないので、削除できます.
プログラムではサイズがSIZEのグローバル配列を定義する.グローバル変数であるため、ランタイム配列は自動的にゼロに初期化されます.次の文は、インデックス20の位置にある要素を50に設定し、find()アルゴリズムを使用して値50を検索します.
iarray[20] = 50;
int* ip = find(iarray, iarray + SIZE, 50);

find()関数は3つのパラメータを受け入れます.最初の2つは、検索の範囲を定義します.CとC++配列はポインタに等しいため、式iarrayは配列の最初の要素を指す.一方、2番目のパラメータiarray+SIZEはpast-the-end値、すなわち配列内の最後の要素の後ろの位置に等しい.3番目のパラメータは、位置決めされる値、すなわち50です.find()関数は、整数を指すポインタipである前の2つのパラメータと同じタイプの反復器を返します.
ヒント
STLはテンプレートを使用することを覚えておく必要があります.従って、STL関数は、それらが使用するデータ型に基づいて自動的に構築される.
find()が成功したかどうかを判断するために、例ではipとpast-the-endの値が等しいかどうかをテストします.
if (ip == iarray + SIZE) ...

式が真の場合、検索範囲に指定された値がないことを示します.それ以外の場合は、正当なオブジェクトへのポインタです.次の文で表示できます.
cout << *ip << " found in array" << endl;

関数の戻り値とNULLが等しいかどうかをテストするのは正しくありません.次のように使用しないでください.
int* ip = find(iarray, iarray + SIZE, 50);
if (ip != NULL) ...  // ??? incorrect

STL関数を使用する場合、ipがpast-the-end値と等しいかどうかをテストするしかありません.この例ではipはC++ポインタであるにもかかわらず、STL反復器のルールに合致する必要がある.
コンテナ反復器
C++ポインタも反復器ですが、容器反復器を使うことが多いです.容器反復器の使い方とiterdemo.cppと同様ですが、ポインタ変数として反復器を明示するのとは異なり、コンテナクラスメソッドを使用して反復器オブジェクトを取得できます.2つの典型的なコンテナクラス法はbegin()とend()である.ほとんどのコンテナでは、コンテナの範囲全体を表します.他のコンテナではrbegin()メソッドとrend()メソッドを使用して、オブジェクト範囲を逆順序で指定する逆反復器も用意されています.
次のプログラムでは、ベクトルコンテナ(STLの配列と等価なオブジェクト)を作成し、反復器を使用して検索します.このプログラムは前章のプログラムと同じです.
Listing 2. vectdemo.cpp
#include 
#include 
#include 
using namespace std;
vector intVector(100);
void main()
{
  intVector[20] = 50;
  vector::iterator intIter =
  find(intVector.begin(), intVector.end(), 50);
  if (intIter != intVector.end())
  cout << "Vector contains value " << *intIter << endl;
  else
  cout << "Vector does not contain 50" << endl;
}

注意検索したデータを次の方法で表示します.
cout << "Vector contains value " << *intIter << endl;

コンスタント反復器
ポインタと同じように、反復器に値を割り当てることができます.たとえば、まず反復器を説明します.
vector::iterator first;

この文はvectorクラスの反復器を作成します.次の文では、反復器をintVectorの最初のオブジェクトに設定し、そのオブジェクトの値を123に設定します.
first = intVector.begin();
*first = 123;

この割り当ては、読み取り専用変数を除いて、ほとんどのコンテナクラスで許可されます.エラー付与を防止するために、反復器は次のように指定できます.
const vector::iterator result;
result = find(intVector.begin(), intVector.end(), value);
if (result != intVector.end())
  *result = 123;  // ???

警告
もう1つのデータの変更を防止する方法は、コンテナをconstタイプとして宣言することである.
テキストアドレスhttp://blog.chinaunix.net/u2/82382/showart_1773401.html