나만의 작은 도서관
[C++][STL] 반복자(Iterator) 본문
반복자(Iterator)란?
- STL의 구성 요소(반복자, 컨테이너, 알고리즘) 중 하나.
- STL은 Standard Template Library의 약자로, C++에서 템플릿을 이용해 정리해 둔 표준 라이브러리를 말한다.
- 반복자는 원소에 접근할 수 있도록 컨테이너가 내부적으로 들고 있는 포인터 역할을 하는 “객체”이다 (포인터가 아니다)
- 반복자는 포인터처럼 작동되도록 역참조(*)나 증감 연산자(it++, ++it)와 같은 연산자들이 오버로딩 되어있다.
- 그냥 포인터랑 정확히 똑같이 작동한다고 생각하면 된다.
iterator
- 기본 반복자 타입.
- begin(), end() 함수가 iterator를 반환한다.
- begin()는 첫번째 원소를 가리키는 반복자를, end()는 마지막 원소 뒤를 가리키는 반복자를 반환한다.
- begin(), end() 계열의 함수들은 반복자를 지원하는 각 컨테이너에 정의되어있다.
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int>::iterator it = v1.begin();
for(; it != v1.rend(); it++){
cout << *it << ' ';
}
cout << '\n';
실행 결과
1 2 3 4 5
const _iterator
- const 포인터와 같은 역할을 한다. const_iterator가 가리키고 있는 원소의 값을 수정할 수 없다.
- cbegin(), cend()가 const_iterator를 반환한다.
- 각각 begin()과 end()가 반환하는 반복자와 같은 곳을 가리킨다.
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int>::const_iterator c_it = v1.cbegin();
// *c_itr = 10; // 식이 수정할 수 있는 lvalue여야 합니다.
reverse_iterator
- 거꾸로 이동하는 반복자.
- rbegin(), rend()가 reverse_iterator를 반환한다.
- rbegin()는 마지막 원소를 가리키는 반복자를, rend()는 첫번째 원소 앞을 가리키는 반복자를 반환한다.
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int>::reverse_iterator r_it = v1.rbegin();
for(; r_it != v1.rend(); r_it++){
cout << *r_it << ' ';
}
cout << '\n';
실행 결과
5 4 3 2 1
const_reverse_iterator
- const 속성을 가진 reverse_iterator 반복자.
- crbrgin(), crend()가 const_reverse_iterator를 반환한다.
- 각각 rbegin()과 rend()가 반환하는 반복자와 같은 곳을 가리킨다.
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int>::const_reverse_iterator cr_it = v1.crbegin();
for(; cr_it != v1.rend(); cr_it++){
cout << *cr_it << ' ';
// *cr_it = 10; // 식이 수정할 수 있는 lvalue여야 합니다.
}
cout << '\n';
실행결과
5 4 3 2 1
[C++11] 범위 기반 for문(range based for loop)
- C++11부터 범위 기반(range-based) for문이 생겼다.
- 범위 기반 for문은 컨테이너 원소를 for문으로 순차적으로 접근하려 할 때 보다 간단하게 표현할 수 있는 방식이다.
vector<int> v1 = {1, 2, 3, 4, 5};
// "기본적인" 범위 기반 for문(값을 복사하므로 원본은 수정 X)
for(int elem : v1){
cout << elem << ' ';
}
// "레퍼런스를 사용한" 범위 기반 for문(자주 보이는 패턴)
for(const int& elem : v1){
cout << elem << ' ';
}
// "auto 타입을 사용한" 범위 기반 for문(개인적으로 별로 안좋아하는 방식)
for(const auto& elem : v1){
cout << elem << ' ';
}
반복자 오버로딩
반복자도 오버로딩이 가능하다. 새로운 클래스에서 반복자를 사용하고 싶은 경우 사용한다.
#include <iostream>
#include <vector>
using namespace std;
class MyContainerIterator
{
public:
MyContainerIterator(int* p) : ptr(p) {}
/* 연산자 오버로딩 */
int& operator*() { return *ptr; }
MyContainerIterator& operator++() { ++ptr; return *this; }
MyContainerIterator operator++(int) { MyContainerIterator temp = *this; ++ptr; return temp; }
bool operator==(const MyContainerIterator& other) const { return ptr == other.ptr; }
bool operator!=(const MyContainerIterator& other) const { return ptr != other.ptr; }
private:
int* ptr;
};
class MyContainer
{
public:
MyContainer(std::initializer_list<int> init) : data(init) {}
/* 반복자 begin(), end() 정의*/
MyContainerIterator begin() { return MyContainerIterator(data.data()); }
MyContainerIterator end() { return MyContainerIterator(data.data() + data.size()); }
private:
std::vector<int> data;
};
int main() {
MyContainer container = {1, 2, 3, 4, 5};
// 반복자 for 루프
for (auto it = container.begin(); it != container.end(); ++it)
cout << *it << " ";
cout << '\n';
// 범위 기반 for 루프
for(auto it : container)
cout << it << " ";
cout << '\n';
return 0;
}
실행결과
1 2 3 4 5
1 2 3 4 5
참고자료
'C++ > 문법 및 메소드(STL)' 카테고리의 다른 글
[C++][STL Container] 시퀀스 컨테이너 #1. 벡터(vector) (0) | 2025.03.15 |
---|---|
[C++][STL] 컨테이너(Container) (0) | 2025.03.14 |
[C++] 레퍼런스(Reference) (0) | 2025.03.13 |
[C++] 포인터(Pointer) (0) | 2025.03.13 |
[C++][Keyword] 열거형(enum, enum class) (0) | 2025.02.19 |