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가지) 카테고리로 분류합니다.
입력 이터레이터 (Input Iterator)
섹션 제목: “입력 이터레이터 (Input Iterator)”단방향, 읽기 전용, 단일 패스.
// istream_iterator: 표준 입력을 이터레이터로std::istream_iterator<int> in(std::cin);std::istream_iterator<int> eof;
std::vector<int> nums(in, eof); // cin에서 모든 int 읽기출력 이터레이터 (Output Iterator)
섹션 제목: “출력 이터레이터 (Output Iterator)”단방향, 쓰기 전용, 단일 패스.
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());이터레이터 어댑터
섹션 제목: “이터레이터 어댑터”reverse_iterator
섹션 제목: “reverse_iterator”컨테이너를 역방향으로 순회합니다.
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 << " ";}insert_iterator 계열
섹션 제목: “insert_iterator 계열”삽입 연산을 이터레이터 인터페이스로 감쌉니다.
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: 지정 위치에 insertstd::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}move_iterator
섹션 제목: “move_iterator”역참조 시 이동 의미론을 적용합니다.
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); // 50auto 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); // 15C++20 Ranges와 이터레이터
섹션 제목: “C++20 Ranges와 이터레이터”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 36sentinel
섹션 제목: “sentinel”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| 카테고리 | 컨테이너 예시 | 특징 |
|---|---|---|
| Input | istream | 읽기, 단일 패스 |
| Output | ostream | 쓰기, 단일 패스 |
| Forward | forward_list | 단방향, 다중 패스 |
| Bidirectional | list, map | 양방향 이동 |
| Random Access | vector, deque | O(1) 임의 접근 |
| Contiguous | vector, array | 메모리 연속성 보장 |
이터레이터는 STL 알고리즘과 컨테이너를 분리하는 핵심 추상화입니다. 커스텀 컨테이너에 적절한 이터레이터 카테고리를 구현하면 모든 STL 알고리즘을 바로 사용할 수 있습니다.