C++ チュートリアルのイテレータ

序文

前の 2 つの記事では、主にベクトルと文字列について学びました。これにより、添字を介してベクトル要素または文字列文字にアクセスできることがわかりましたが、この方法以外にも要素を取得するより一般的な方法があります。それはイテレータです。この記事では、イテレータの関連内容を簡単に紹介します。

イテレータの概要

コンテナーを使用して要素を格納する場合、格納されている要素を取得する必要がある場合があり、コンテナーから要素を取得するためにイテレーターが使用されます。基本的にすべてのコンテナー ライブラリはイテレーターをサポートしていますが、それらをサポートしているのはごく一部です。マークして要素を取得します。string はコンテナではありませんが、添字やイテレータを含む多くのコンテナ操作をサポートします。

ポインタと同様に、イテレータはオブジェクトを取得する間接的な方法を提供します。イテレータの場合、このオブジェクトはコンテナ内の要素または文字列内の文字です。イテレータを通じて要素を取得できますが、同時に、ポイントされたオブジェクトは、あるオブジェクトから次のオブジェクトに移動します。イテレータもポインタと同様に有効と無効があり、要素を表す次の位置またはコンテナ内の最後の要素はすべて有効で、その他のイテレータはすべて無効です。

イテレータの使用

ポインタとは異なり、反復子を取得するために address-of 演算子を使用しません。反復子をサポートするすべての型には、反復子を返す関数があります。これらの型には、begin および end という名前の関数があります。begin は、要素の最初の反復子を返します。反復子end によって返されるのは、コンテナまたは文字列の最後の要素の次の位置です。この反復子は、存在しない要素である最後の要素の次の位置を表します。コンテナが空の場合、begin と end は同じイテレータを返します。

auto b = v.begin(), e = v.end()

イテレータ操作

イテレータは、以下の表にリストされている操作のみをサポートします。== または != を使用して 2 つの有効なイテレータを比較できます。イテレータが同じ要素を表すか、最後の要素の次の位置である場合、それらは等しく、それ以外の場合は待機します。
|操作|説明|
|*iter| はイテレータによって表されるポインタが指す値を返します|
|iter->mem| は (*iter).mem と同等です|
|++iter| の次の要素を指しますコンテナ|
|- iter|コンテナ内の前の要素を指します|
|iter1 == iter2|2 つのイテレータが等しいかどうかを判断|
|iter1 != iter2|2 つのイテレータが等しくないかどうかを判断|

ポインタの場合、逆参照を使用してイテレータの要素を取得できます。ポインタと同様に、有効なイテレータの要素は逆参照を通じてのみ取得できます。最後の要素の後にイテレータを逆参照した場合、結果は不明です。

# include<iostream>
# include<string>
using namespace std;


int main() {
  string s("some string");
  if (s.begin() != s.end()) {
    auto it = s.begin();
    *it = toupper(*it);
  }
  cout<<s<<endl;
  }

上の例は、反復子を通じて文字列 s の最初の文字を取得し、大文字にします。

イテレータはある要素から別の要素に移動します

イテレータは、自己インクリメント演算子をプライベートに使用して、要素のある要素から次の要素に移動します。イテレータの自己インクリメントは、整数の自己インクリメントと非常によく似ています。整数の場合、自己インクリメントとはそれ自体の値です。反復子の場合、その効果は 1 位置進みます。

end は要素を返さないため、インクリメントまたは逆参照することはできません。

インクリメント操作を使用すると、前のプログラムを書き直すことができます。

# include<iostream>
# include<string>
using namespace std;


int main() {
  string s("some string");
  for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it) {
    *it = toupper(*it);
  }
  cout<<s<<endl;
  }

上の例に示すように、反復子を介したループ トラバーサルを実装できます。

イテレータ型

ベクトルの正確な型や文字列のサイズが正確にわからないのと同様に、反復子の正確な型もわかりませんし、知る必要もありませんが、次の種類の反復子は次の規則に従って定義されます。イテレータの読み取りおよび書き込み権限:

 vector<int>::iterator it; //it可以读也可以写vector<int>的元素
  string::iterator it2; //it2可以读写字符串里的字符
  vector<int>::const_iterator it3; //it3可以读但是不可以写元素
  string::const_iterator it4; //it4可以读但是不可以写字符串里面的字符

const_iterator は定数ポインタのように動作し、要素は読み取ることはできますが、書き込むことはできません

操作の開始と終了

begin と end によって返される結果は、操作するオブジェクトが定数かどうかによって異なります。オブジェクトが定数の場合、begin と end は const_iterator を返します。オブジェクトが定数でない場合は、iterator を返します。

# include<iostream>
# include<string>
# include<vector>
using namespace std;


int main() {
vector<int> v;
const vector<int> cv;
auto it1 = v.begin(); //it返回的是vector<int>::iterator
auto it2 = v.begin(); //it返回的是vector<int>::const_iterator
}

このデフォルトの戻り戦略は要件を満たさない場合があります。場合によっては、要素が変更されるのを避けるために、一部の非定数ベクトルの要素のみを読み取りたい場合があります。次の新しいメソッド cbegin および cend が C++11 で提供されます。 vetor が定数であるかどうか、const_iterator を返します。

auto it3 = v.cbegin();

反復子に対する数学的演算

前述の自己インクリメントと自己デクリメントに加えて、イテレータは次の数学演算もサポートしています。イテレータには添字の概念がありませんが、次の演算は添字の演算として理解できます。減算にはセルフインクリメントとセルフデクリメントがあり、減算の一般的な形式は前方または後方への移動であり、大小比較は前後の位置の比較です。

操作する 説明
イター + n 同じコンテナを前方に移動 n
イター - n 同じコンテナが後方に移動しました
iter1 += n 移動結果を iter1 に代入する
iter1 -= n 移動結果を iter1 に代入する
>、>=、<、<= 相対位置の比較

このように言うと、また抽象化されてしまうかもしれません。二分法を使って説明してみましょう。

# include<iostream>
# include<string>
# include<vector>
using namespace std;


int main() {
  vector<int> v = {1, 2, 3, 4, 5};
  auto beg = v.begin(), end = v.end();
  auto mid = v.begin() + (end - beg) / 2;
  int target = 2;
  while (mid != end && *mid != target)
  {
    if (target < *mid) {
      end = mid;
    } else{
      beg = mid;
    }
    mid = beg + (end - beg) / 2;
  }
  cout<<to_string(*mid)<<endl;
  }

上の例では、要素 2 の位置である 2 が出力されます。

やっと

この記事では主に C++ のイテレータについて紹介しますが、その他の記事については公式アカウント QStack をご覧ください。

おすすめ

転載: blog.csdn.net/QStack/article/details/129133599