[STL] 반복자(1)
in STL
반복자의 종류
반복자는 포인터를 추상화한 클래스 객체다. 그래서 포인터가 하지 못하는 더 많은 동작을 할 수 있다. 자료 형식이 있어 효율적인 연산이 가능하듯이 반복자도 각 반복자만의 특징을 가지는 다음 다섯 가지의 반복자가 있다.
- 입력 반복자(input iteraotr) : 전방향 읽기(istream)
- *iter(읽기), ->(멤버 읽기), ++(전방향 이동), ==(비교), !=(비교), iterator(iter)연산을 제공한다.
- 출력 반복자(output iterator) : 전방향 쓰기(ostream)
- *iter=x(쓰기), ++, iterator(iter) (복사 생성자) 연산을 제공한다.
- 순방향 반복자(forward iterator) : 전방향 읽기, 쓰기
- *iter, ->, ++, ==, !=, =(대입),iterator() (기본 생성자), iterator(iter) 연산을 제공한다.
- 양방향 반복자(bidirectional iterator) : 양방향 읽기, 쓰기(list, set, multiset, map, multimap)
- 순방향 반복자 기능에 –(역방향 이동) 연산을 제공한다.
- 임의 접근 반복자(random access iterator) : 랜덤 읽기, 쓰기(vector, deque)
- 양방향 반복자 기능에 반복자의 랜덤 연산인 [],+=, -=, +, -, <, >, <=, >=연산을 제공한다.
X::iterator와 X::const_iterator
- x::iterator : 정방향 반복자의 내장 형식, 반복자가 가리키는 원소 읽기, 쓰기 가능
- x::const_iterator : 정방향 반복자의 내장 형식, 반복자가 가리키는 원소 읽기만 가능
아래 예제는 iterator와 const_iterator 반복자의 읽기와 쓰기 관련 예제이다.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void main()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
cout << "v[iterator 읽기 가능] : ";
for (vector<int>::iterator iter = v.begin(); iter != v.end(); iter++) {
cout << *iter << " ";
}
cout << endl;
cout << "v[const iterator 읽기 가능] : ";
for (vector<int>::const_iterator citer = v.begin(); citer != v.end(); citer++) {
cout << *citer << " ";
}
cout << endl;
vector<int>::iterator iter = v.begin();
vector<int>::const_iterator citer= v.begin();
*iter = 100; // 쓰기 가능
//*citer = 100; 쓰기 불가능 const_iterator 형식의 반복자가 가리키는 원소는 수정 불가
}
그리고 반복자가 가리키는 원소의 위치를 바꾸지 않으려면 const 키워드를 이용해 상수화가 가능하다.
아래 예제는 모든 경우의 상수화를 다루는 예제이다.
#include <iostream>
#include <vector>
using namespace std;
void main()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
vector<int>::iterator iter = v.begin();
vector<int>::const_iterator citer = v.begin()+1;
const vector<int>::iterator const_iter = v.begin()+2;
const vector<int>::const_iterator const_citer = v.begin()+3;
// iter은 모두 가능
*iter = 100; // 가리키는 원소 값 변경 가능
++iter; // 반복자 위치 변경 가능
// citer
// *citer=100; // 가리키는 원소 값 변경 불가능
++citer; // 반복자 위치 변경 가능
// const_iter
*const_iter = 300; // 가리키는 원소 값 변경 가능
// ++const_iter; // 반복자 위치 변경 불가능
// const_citer
// *const_citer=400; // 가리키는 원소 값 변경 불가능
// ++const_citer; // 반복자 위치 변경 불가능
}
X::reverse_iterator와 X::const_reverse_iterator
- X::reverse_iterator : 역방향 반복자의 내장 형식, 반복자가 가리키는 원소 읽기, 쓰기 가능
- x::Const_reverse_iterator : 역방향 반복자의 내장 형식, 반복자가 가리키는 원소의 읽기만 가능
컨테이너의 rbegin() 멤버 함수는 컨테이너 순차열의 끝 표시 반복자이다. rend() 멤버 함수는 순차열의 첫 원소를 가리키는 반복자를 반환한다.
아래 예제는 정방향 반복자와 역방향 반복자를 비교한 예제이다.
#include <iostream>
#include <vector>
using namespace std;
void main()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
cout << "v[iterator] : ";
for (vector<int>::iterator iter = v.begin(); iter != v.end(); iter++) {
cout << *iter << " ";
}
cout << endl;
cout << "v[reverse_iterator] : ";
for (vector<int>::reverse_iterator riter = v.rbegin(); riter != v.rend(); riter++) {
cout << *riter << " ";
}
cout << endl;
}
iter는 ++하면 정방향으로 이동하지만, riter은 ++하면 역방햐으로 움직인다. 그리고 주의할 점은 역방향 반복자는 실제 가리키고 있는 곳의 다음 원소의 값을 참조한다.
X::reverse_iterator와 X::const_reverse_iterator 형식은 반복자 어댑터 reverse_iterator<T>를 사용해 X::iterator와 x::const_iterator를 반대로 동작하도록 변환한 형식이다. 아래 예제를 보자.
#include <iostream>
#include <vector>
using namespace std;
void main()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
// reverse_iterator 어댑터로 정방향 반복자를 역방향 반복자로 변환
reverse_iterator<vector<int>::iterator> rbiter(v.end());
reverse_iterator<vector<int>::iterator> reiter(v.begin());
cout << "v [rbiter, reiter) : ";
for (; rbiter != reiter; rbiter++) {
cout << *rbiter << " ";
}
cout << endl;
cout << "v [rbegin(), rend()) : ";
for (vector<int> ::const_reverse_iterator riter = v.rbegin(); riter != v.rend();riter++) {
cout << *riter << " ";
}
cout << endl;
}
아래 예제는 네 반복자 X::iterator와 X::const_iterator와 X::reverse_iterator와 X::const_reverse_iterator 형식의 형변환을 보여주는 예제이다.
#include <iostream>
#include <vector>
using namespace std;
void main()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
vector<int>::iterator iter = v.begin() + 1;
vector<int>::const_iterator citer = iter;
// vector<int>::reverse_iterator riter(iter);와 같다.
reverse_iterator<vector<int>::iterator> riter(iter);
// vector<int>::const_reverse_iterator criter(riter)과 같다.
reverse_iterator<vector<int>::const_iterator> criter(riter);
cout << "iter : " << *iter << endl;
cout << "citer : " << *citer << endl;
cout << "riter : " << *riter << endl;
cout << "criter : " << *criter << endl;
cout << "----------------------------------------------------" << endl;
cout << "riter.base() => iter : " << *riter.base() << endl;
cout << "criter.base() => citer : " << *criter.base() << endl;
}
포인터처럼 비 const 반복자는 const 반복자로 형변환되며 정방향 반복자는 역방향 반복자로 암묵적 변환(생성자를 이용한)됩니다. 역방향 반복자는 base() 멤버 함수를 사용하여 정방향 반복자로 형변환 할 수 있다.
네 반복자의 형식 변환을 그림으로 표현한 것이다.