콘텐츠로 이동

C++ STL Iterator & Adaptor

이터레이터(Iterator)는 컨테이너의 요소를 순회하기 위한 일반화된 포인터입니다. 알고리즘이 컨테이너 타입에 독립적으로 동작할 수 있게 해주는 STL의 핵심 추상화입니다.

std::vector<int> v = {1, 2, 3, 4, 5};
// 포인터와 동일한 인터페이스
auto it = v.begin();
*it = 10; // 역참조
++it; // 전진
it += 2; // 임의 접근 (vector iterator만 가능)

STL은 이터레이터를 5가지(C++17 이후 6가지) 카테고리로 분류합니다.

단방향, 읽기 전용, 단일 패스.

// istream_iterator: 표준 입력을 이터레이터로
std::istream_iterator<int> in(std::cin);
std::istream_iterator<int> eof;
std::vector<int> nums(in, eof); // cin에서 모든 int 읽기

단방향, 쓰기 전용, 단일 패스.

std::ostream_iterator<int> out(std::cout, ", ");
std::copy(nums.begin(), nums.end(), out);

순방향 이터레이터 (Forward Iterator)

섹션 제목: “순방향 이터레이터 (Forward Iterator)”

단방향, 읽기/쓰기, 다중 패스. std::forward_list, std::unordered_map 등.

양방향 이터레이터 (Bidirectional Iterator)

섹션 제목: “양방향 이터레이터 (Bidirectional Iterator)”

앞뒤 이동 가능. std::list, std::map, std::set 등.

std::list<int> lst = {1, 2, 3};
auto it = lst.end();
--it; // 뒤로 이동 가능

임의 접근 이터레이터 (Random Access Iterator)

섹션 제목: “임의 접근 이터레이터 (Random Access Iterator)”

O(1) 임의 접근. std::vector, std::deque, 배열.

std::vector<int> v = {1, 2, 3, 4, 5};
auto it = v.begin();
it += 3; // O(1) 이동
auto dist = v.end() - v.begin(); // 거리 계산

연속 이터레이터 (Contiguous Iterator, C++17)

섹션 제목: “연속 이터레이터 (Contiguous Iterator, C++17)”

메모리 연속성 보장. std::vector, std::array, std::string.

// 포인터로 변환 보장
int* ptr = std::to_address(v.begin());

컨테이너를 역방향으로 순회합니다.

std::vector<int> v = {1, 2, 3, 4, 5};
// rbegin/rend: reverse_iterator 반환
for (auto it = v.rbegin(); it != v.rend(); ++it)
{
std::cout << *it << " "; // 5 4 3 2 1
}
// 범위 기반 for와 함께
for (auto& x : std::views::reverse(v))
{
std::cout << x << " ";
}

삽입 연산을 이터레이터 인터페이스로 감쌉니다.

std::vector<int> src = {1, 2, 3};
std::vector<int> dst;
// back_insert_iterator: push_back으로 삽입
std::copy(src.begin(), src.end(), std::back_inserter(dst));
// front_insert_iterator: push_front (list, deque)
std::list<int> lst;
std::copy(src.begin(), src.end(), std::front_inserter(lst));
// insert_iterator: 지정 위치에 insert
std::vector<int> v = {1, 2, 4, 5};
auto pos = std::find(v.begin(), v.end(), 4);
std::copy(src.begin(), src.begin() + 1, std::inserter(v, pos));
// v = {1, 2, 1, 4, 5}

역참조 시 이동 의미론을 적용합니다.

std::vector<std::string> src = {"hello", "world", "foo"};
std::vector<std::string> dst;
// 복사 대신 이동 → src의 문자열은 이동 후 빈 문자열
std::move(src.begin(), src.end(), std::back_inserter(dst));

std::list<int> lst = {10, 20, 30, 40, 50};
// std::advance: n 칸 이동 (양방향 이터레이터도 지원)
auto it = lst.begin();
std::advance(it, 3); // 30을 가리킴
// std::distance: 두 이터레이터 사이 거리
auto dist = std::distance(lst.begin(), it); // 3
// std::next, std::prev: 복사본 이동
auto next2 = std::next(it, 2); // 50
auto prev1 = std::prev(it, 1); // 20

C++ 이터레이터를 직접 구현할 때 필요한 멤버를 정의합니다.

class Range
{
public:
class Iterator
{
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = int;
using difference_type = std::ptrdiff_t;
using pointer = const int*;
using reference = int;
explicit Iterator(int value) : _value(value) {}
reference operator*() const { return _value; }
Iterator& operator++() { ++_value; return *this; }
Iterator operator++(int) { auto tmp = *this; ++(*this); return tmp; }
Iterator& operator--() { --_value; return *this; }
Iterator operator+(difference_type n) const { return Iterator(_value + n); }
difference_type operator-(const Iterator& other) const { return _value - other._value; }
bool operator==(const Iterator& o) const { return _value == o._value; }
bool operator!=(const Iterator& o) const { return _value != o._value; }
bool operator< (const Iterator& o) const { return _value < o._value; }
private:
int _value;
};
Range(int from, int to) : _from(from), _to(to) {}
Iterator begin() const { return Iterator(_from); }
Iterator end() const { return Iterator(_to); }
private:
int _from, _to;
};
// 사용
for (int i : Range(1, 6))
std::cout << i << " "; // 1 2 3 4 5
// STL 알고리즘과 호환
Range r(1, 6);
auto sum = std::accumulate(r.begin(), r.end(), 0); // 15

C++20 <ranges>는 이터레이터를 기반으로 지연 평가 뷰 파이프라인을 제공합니다.

#include <ranges>
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 파이프라인: 짝수만 필터 → 제곱 → 처음 3개
auto result = v
| std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return n * n; })
| std::views::take(3);
for (int x : result)
std::cout << x << " "; // 4 16 36

C++20은 begin()end()의 타입이 달라도 됩니다(sentinel). 무한 시퀀스 표현이 가능합니다.

// iota_view: 무한 정수 시퀀스
auto first_five_squares = std::views::iota(1)
| std::views::transform([](int n) { return n * n; })
| std::views::take(5);
for (int x : first_five_squares)
std::cout << x << " "; // 1 4 9 16 25

카테고리컨테이너 예시특징
Inputistream읽기, 단일 패스
Outputostream쓰기, 단일 패스
Forwardforward_list단방향, 다중 패스
Bidirectionallist, map양방향 이동
Random Accessvector, dequeO(1) 임의 접근
Contiguousvector, array메모리 연속성 보장

이터레이터는 STL 알고리즘과 컨테이너를 분리하는 핵심 추상화입니다. 커스텀 컨테이너에 적절한 이터레이터 카테고리를 구현하면 모든 STL 알고리즘을 바로 사용할 수 있습니다.