[STL] 반복자(1)



반복자의 종류

반복자는 포인터를 추상화한 클래스 객체다. 그래서 포인터가 하지 못하는 더 많은 동작을 할 수 있다. 자료 형식이 있어 효율적인 연산이 가능하듯이 반복자도 각 반복자만의 특징을 가지는 다음 다섯 가지의 반복자가 있다.

  • 입력 반복자(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 형식의 반복자가 가리키는 원소는 수정 불가
}

image

그리고 반복자가 가리키는 원소의 위치를 바꾸지 않으려면 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;
}

image

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;
}

image

아래 예제는 네 반복자 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;
}

image

포인터처럼 비 const 반복자는 const 반복자로 형변환되며 정방향 반복자는 역방향 반복자로 암묵적 변환(생성자를 이용한)됩니다. 역방향 반복자는 base() 멤버 함수를 사용하여 정방향 반복자로 형변환 할 수 있다.

image

네 반복자의 형식 변환을 그림으로 표현한 것이다.




© 2022. by KSC

Powered by sora