404 Not Found

404 Not Found


nginx

STLのイテレータ

[第]34~35[課では、]STLコンテナ[と]アルゴリズム[について学びました。]

[さて]、[ここでは]STLの「接着剤」とも言えるiteratorについて詳しく見ていきましょう。

[イテレータ]を理解してこそ、[STLの設計哲学]を[真に理解できる]。


1. イテレータ[概要]

(1) 1.1 イテレータとは?

イテレータはSTLの[中核となる概念]であり、[コンテナ]と[アルゴリズム]を[結びつける]ものです。

[生活]クラス[比]:


(2) 1.2 イテレータの基本操作

[すべての]イテレータ[は以下の操作をサポートしています]:

[操作] [説明]
*it [解]参照 int x = *it;
it++ [次の要素へ進む] ++it;
it-- [前の要素に戻る] --it;
it1 == it2 [等しい] if (it1 == it2)
it1 != it2 [比較不等] while (it != end())


2. iterator[分]クラス

(1) 2.1 [5種類の]イテレータ

STLでは、5種類のイテレータが定義されており、その機能は[弱いものから強いものへと]順に並んでいます:

反復処理型 [機能] [代表例]コンテナ
inputiterator [読み取り専用],[一方向] istream_iterator
出力イテレータ [書き込み専用],[一方向] ostream_iterator
[順方向]イテレータ [読み書き],[一方向] forward_list
[双方向]イテレータ [読み書き]、[双方向] listsetmap
[ランダムアクセス]イテレータ [読み書き]、[ランダムアクセス] vectordequearray

(2) 2.2 イテレータ[能力]の比較

TEXT
 ← 
 ↓

 ↓

 ↓
 ← 

[能力が高ければ高いほど]、[対応する操作も増える]:

[操作] 入力 [順方向] [双方向] [ランダムアクセス]
[解]reference *
[次へ] ++
[戻る] --
[ランダムアクセス] ``
[算術演算] + -

(3) 2.3 の例:[異なる]コンテナ[の]イテレータ

CPP
#include iostream
#include vector
#include list
#include forward_list

int main() {
 std::vectorint v = {1, 2, 3};
 std::listint l = {1, 2, 3};
 std::forward_listint fl = {1, 2, 3};
 
 // vector:iterator
 auto it_v = v.begin();
 std::cout << it_v[2] << std::endl; // 
 
 // list:iterator
 auto it_l = l.begin();
 ++it_l; // ...
 --it_l; // ...
 // it_l[2]; // ❌!list
 
 return 0;
}


3. イテレータ[無効]

(1) 3.1 イテレータ[失効]とは何か?

イテレータ[無効化]とは、コンテナ[に対する操作の後]、イテレータ[が指していた位置が][無効]になることを指します。

[よくある原因]:


(2) 3.2 [異なる]コンテナ[の]イテレータ[の無効化ルール]

コンテナ [操作] [無効となる状況]
vector push_back [無効になる可能性あり]([再割り当て時])
vector erase [削除された要素およびそれ以降の]イテレータ[無効]
list push_back [失効なし]
list erase [削除された要素のみを含む]イテレータ[無効]
map/set erase [削除された要素のみを含む]イテレータ[無効]

(3) 3.3 例:vectoriterator[無効] (難易度 ⭐⭐)

▶ サンプル 1: STLコンテナ[の使用] (難易度 ⭐)

CPP
#include iostream
#include vector

int main() {
 std::vectorint v = {1, 2, 3, 4, 5};
 
 auto it = v.begin();
 std::cout << "*it = " << *it << std::endl; // output:1
 
 // push_back,iterator
 v.push_back(6);
 
 // ❌!it
 // std::cout << "*it = " << *it << std::endl; // ...
 
 // ✅:iterator
 it = v.begin();
 std::cout << "*it = " << *it << std::endl; // output:1
 
 return 0;
}
▶ 試してみよう

(4) 3.4 [要素の安全な削除]

エラー[作り方]:

CPP
for (auto it = v.begin(); it != v.end(); ++it) {
### (5) ▶ 2:C++(⭐)

 if (*it % 2 == 0) {
 v.erase(it); // ❌ it!
 }
}

[正しい方法]:

CPP
for (auto it = v.begin(); it != v.end(); ) {
 if (*it % 2 == 0) {
 it = v.erase(it); // ✅ erasereturnYesiterator
 } else {
 ++it;
 }
}


4. [逆方向]イテレータ

(1) 4.1 [逆]イテレータとは何か?

[逆方向]イテレータは、[コンテナ]の[末尾から先頭に向かって]走査します。

例:[逆順]の出力 (難易度 ⭐)

CPP
#include iostream
#include vector

int main() {
 std::vectorint v = {1, 2, 3, 4, 5};
 
 // ...
 for (auto it = v.rbegin(); it != v.rend(); ++it) {
 std::cout << *it << " ";
 }
 std::cout << std::endl;
 
 return 0;
}

[実行結果]:

TEXT
5 4 3 2 1 


5. [挿入]イテレータ

(1) 5.1 [挿入]イテレータとは何か?

[挿入]イテレータは、[コンテナに]要素を****[挿入する]ために[使用される][出力]イテレータです。

[3種類の挿入]イテレータ:

イテレータ [機能]
back_inserter [末尾に挿入] std::back_inserter(v)
front_inserter [先頭挿入] std::front_inserter(l)
inserter [指定位置に挿入] std::inserter(v, v.begin())

(2) 5.2 例:[用]back_inserter[コピー] (難易度 ⭐⭐)

CPP
#include iostream
#include vector
#include algorithm
#include iterator

int main() {
 std::vectorint src = {1, 2, 3, 4, 5};
 std::vectorint dst; // ...
 
 // ❌!dst
 // std::copy(src.begin(), src.end(), dst.begin());
 
 // ✅!Usingback_inserter
 std::copy(src.begin(), src.end(), std::back_inserter(dst));
 
 std::cout << ":";
 for (int x : dst) {
 std::cout << x << " ";
 }
 std::cout << std::endl;
 
 return 0;
}


6. ストリームイテレータ

(1) 6.1 入力ストリームイテレータ

[機能]: [inputstreamから]データを[読み込む]。

例:[標準]入力[から読み取り] (難易度 ⭐⭐)

CPP
#include iostream
#include vector
#include iterator

int main() {
 std::vectorint v;
 
 std::cout << "(Ctrl+Z):" << std::endl;
 
 // ...
 std::copy(std::istream_iteratorint(std::cin),
 std::istream_iteratorint(),
 std::back_inserter(v));
 
 std::cout << ":";
 for (int x : v) {
 std::cout << x << " ";
 }
 std::cout << std::endl;
 
 return 0;
}

(2) 6.2 出力ストリームイテレータ

[機能]: [outputstream]に[データを書き込む]。

例:output[to]file (難易度 ⭐⭐)

CPP
#include iostream
#include vector
#include iterator
#include fstream

int main() {
 std::vectorint v = {1, 2, 3, 4, 5};
 
 // outputoutput
 std::copy(v.begin(), v.end(),
 std::ostream_iteratorint(std::cout, " "));
 std::cout << std::endl;
 
 // output
 std::ofstream file("output.txt");
 std::copy(v.begin(), v.end(),
 std::ostream_iteratorint(file, "\n"));
 file.close();
 
 return 0;
}

❓ よくある質問

Q [なぜ]リスト[はランダムアクセスに対応していない]のですか?
A list [リストは連結リスト]であり、[要素は]メモリ[内で連続していない]ため、[インデックスを使って直接アクセスすることはできない]からです。

Q イテレータの[無効化]を避けるには?
A 1. [毎回]コンテナ[を操作した後]、イテレータを[再取得]する 2. eraseの[戻り値]を使ってイテレータを[更新]する 3. [できるだけ]アルゴリズムを使用し、イテレータへの[手動操作]を控える

Q:const_iteratorとは何ですか? A:const_iterator [読み取り専用]のイテレータであり、[要素の値を修正することはできません]。

CPP
std::vectorint v = {1, 2, 3};
std::vectorint::const_iterator it = v.cbegin();
// *it = 10; // ❌!modify

📖 まとめ

[知識ポイント] [要点]
iterator[分]クラス 入力→[順方向]→[双方向]→[ランダムアクセス]
iterator[無効] vector[無効になる可能性あり],list[無効にならない]
[逆方向]イテレータ rbegin()/rend()
[挿入]イテレータ back_inserter[など]
streamiterator [STLと]IO

📝 練習問題

  1. **初心者(難易度 ⭐):[iterator] を使用して vectorint を [遍歴] し、[すべての要素] を出力する。[begin] と [end] を使用する方法と、[for] ループを使用する方法の [2つの方法] でそれぞれ行う。

  2. **中級(難易度 ⭐⭐):[逆順]イテレータ rbegin/rend を使用して [ベクトルを逆順に走査]し、[結果を]出力する。[順方向の走査との違いを観察する]。

  3. **上級(難易度 ⭐⭐⭐):[カスタム]イテレータを実装し、[整数の範囲]([例えば] 1 [から] 10)を[ラップ]し、[++] [および] [*] [演算子]を[サポート]する。



[次のレッスン]:STLの関数オブジェクト(#38)

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%