目次
はじめに
C++のstd::copy
のようなアルゴリズムは、通常、既にある範囲の要素を上書きします。そのため、結果を格納する先のコンテナは、あらかじめ十分な大きさで確保されている必要がありました。
この問題を解決するのが「挿入イテレータ」です。挿入イテレータは、通常の代入操作 (*it = value;
) を、実際にはコンテナのメンバ関数(.push_back()
など)の呼び出しに変換します。これにより、出力先のコンテナのサイズを気にすることなく、アルゴリズムの結果を動的に追加していくことができます。
この記事では、<iterator>
ヘッダーで提供される、3種類の主要な挿入イテレータを解説します。
std::back_inserter
: コンテナの末尾に追加する (.push_back()
)。std::front_inserter
: コンテナの先頭に追加する (.push_front()
)。std::inserter
: コンテナの指定した位置に追加する (.insert()
)。
挿入イテレータのサンプルコード
このコードは、source
ベクターから偶数の要素だけを、3種類の挿入イテレータを使って、それぞれlist
コンテナにコピーします。
完成コード
#include <iostream>
#include <vector>
#include <list>
#include <iterator> // back_inserter, front_inserter, inserter
#include <algorithm> // copy_if
using namespace std;
// listの内容を表示するヘルパー関数
void print_list(const string& title, const list<int>& l) {
cout << title << ": ";
for (int val : l) {
cout << val << " ";
}
cout << endl;
}
int main() {
vector<int> source = {1, 2, 3, 4, 5, 6};
auto is_even = [](int n){ return n % 2 == 0; }; // 条件(偶数)
// --- 1. back_inserter: 末尾に追加 ---
list<int> dest1;
copy_if(source.begin(), source.end(), back_inserter(dest1), is_even);
print_list("back_inserter (末尾追加)", dest1);
// --- 2. front_inserter: 先頭に追加 ---
list<int> dest2;
copy_if(source.begin(), source.end(), front_inserter(dest2), is_even);
print_list("front_inserter (先頭追加)", dest2);
// --- 3. inserter: 指定位置に追加 ---
list<int> dest3 = {100, 200};
copy_if(source.begin(), source.end(), inserter(dest3, next(dest3.begin())), is_even);
print_list("inserter (中間追加)", dest3);
return 0;
}
実行結果
back_inserter (末尾追加): 2 4 6
front_inserter (先頭追加): 6 4 2
inserter (中間追加): 100 2 4 6 200
各挿入イテレータの解説
1. std::back_inserter
- 動作: コンテナの
.push_back()
メンバ関数を呼び出します。 - 結果:
source
の偶数2
,4
,6
が、dest1
の末尾に順番に追加されていきます。 - 対応コンテナ:
.push_back()
を持つ全てのコンテナ(vector
,deque
,list
,string
)。
2. std::front_inserter
- 動作: コンテナの
.push_front()
メンバ関数を呼び出します。 - 結果:
2
が先頭に追加され({2}
)、次に4
が先頭に追加され({4, 2}
)、最後に6
が先頭に追加される({6, 4, 2}
)ため、結果は逆順になります。 - 対応コンテナ:
.push_front()
を持つコンテナ(list
,deque
,forward_list
)。
3. std::inserter
- 動作:
inserter(コンテナ, 位置)
のように、挿入を開始したい位置を示すイテレータを第2引数に取ります。コンテナの.insert(位置, 値)
メンバ関数を呼び出します。 - 結果:
dest3
の先頭の次 (next(dest3.begin())
、つまり200
の前) の位置に、2
,4
,6
が順番に挿入されていきます。 - 対応コンテナ:
.insert()
を持つ全てのコンテナ。
まとめ
今回は、C++の挿入イテレータを使って、アルゴリズムの結果をコンテナに動的に追加する方法を解説しました。
back_inserter
: 末尾に追加 (push_back
)。最も一般的。front_inserter
: 先頭に追加 (push_front
)。結果は逆順になる。inserter
: 指定した位置に追加 (insert
)。
出力先のサイズを事前に計算してresize
する手間を省き、より安全で柔軟なコードを書くために、これらの挿入イテレータは非常に有効なツールです。