상세 컨텐츠

본문 제목

[STL] 반복자(1)

C++/C++ STL

by deulee 2023. 8. 23. 13:02

본문

C언어에서 가장 핵심적인 문법은 '포인터'를 선택할 것이다. 그리고 STL의 가장 핵심적인 요소는 바로 '반복자'이다.

 

반복자와 포인터의 역할은 사용 방법이 비슷하지만 훨씬 더 '일반화'되어 있어 임의의 컨테이너와 함께 사용할 수 있다.

 


반복자 이전의 컨테이너 순회 방법

 

1. 배열 순회하기

void Print(int* ar, int num)
{
	for (int i = 0; i < num; i++)
		std::cout << ar[i] << std::endl;
}

첨자를 증가시키면서 '[] 연산자'를 이용해 첨자 위치의 요소를 출력하는 것을 알 수 있다.

 

 

2. 연결 리스트 순회하기

void Print(Node* head)
{
	for (Node* curr = head; curr != tail; curr = head->next)
		std::cout << curr->value << std::endl;
}

첫 번째의 배열 같은 경우는 첨자를 증가시키면 되지만 연결 리스트는 노드들이 다음 노드의 메모리 주소를 가지고 있어 링크를 쫓아 다녀야 모든 노드를 순회할 수 있다.

 

위의 두 컨테이너는 유사함에도 불구하고 물리적인 자료 구조가 틀리므로 순회하는 방법이 다르다.

 

이 때문에 똑같은 작업을 하는 함수임에도 순회 방법이 틀려 각 자료구조에 맞는 함수가 필요하다.

 

이러한 순회 방법을 '일반화'하기 위해 STL에서 사용하는 개념이 바로 '반복자'이다.

 


반복자

우선 순회 방법을 일반화를 위해 다음과 같은 기능을 가진다.

  • 컨테이너의 요소 하나를 가리키는 기본적인 역할
  • 가리키는 지점의 요소를 읽고 쓸 수 있다. 내용을 읽는 '*' 연산자가 정의된다.
  • '증감'에 의해 주변 요소로 이동할 수 있다.
  • 반복자끼리 대입, 비교 가능해야 한다. '대입', '비교 연산자'가 정의된다.

위의 요소는 포인터는 그대로 할 수 있는 것이며 반복자는 이를 흉내낸다고 생각하면 된다.

 

모든 컨테이너는 시작점과 끝다음점을 조사하는 'begin', 'end' '멤버 함수'를 제공한다.


1. 포인터(반복자)를 이용하여 배열 순회하기

int main(void)
{
	int arr[] = {1, 2, 3, 4, 5};

	int* it;
	for (it = &arr[0]; it != &arr[5]; it++)
		std::cout << *it;
	return 0;
}

2. 벡터 순회하기

int main(void)
{
	int arr[] = {1, 2, 3, 4, 5};
	std::vector<int> varr(&arr[0], &arr[5]);

	std::vector<int>::iterator it;
	for (it = varr.begin(); it != varr.end(); it++)
		std::cout << *it;
	return 0;
}

이번 예제에서는 다음과 같은 문구를 볼 수 있다.

std::vector<T>::iterator it;

'vector<T>'가 클래스 이름이고 이 클래스안에 'iterator'라는 타입으로 'typedef'로 정의되어 있으며 이 타입으로 변수를 선언하면 벡터의 한 요소를 가리키는 반복자가 된다.


3. 연결 리스트 순회 방법

int main(void)
{
	int arr[] = {1, 2, 3, 4, 5};
	std::list<int> larr(&arr[0], &arr[5]);

	std::list<int>::iterator it;
	for (it = larr.begin(); it != larr.end(); it++)
		std::cout << *it;
	return 0;
}

 


활용

위의 예제들을 보면 모든 컨테이너들이 반복자를 통해 순회되는 것을 볼 수 있다.

 

즉, 다 똑같은 형태의 구문으로 이루어져있다는 것은 하나의 함수로도 구조가 다른 컨테이너들을 순회할 수 있다는 것이다.

 

#include <iostream>
#include <vector>
#include <list>

template <typename IT>
void Print(IT s, IT e)
{
	IT it;
	for (it = s; it != e; it++)
		std::cout << *it;
}

int main(void)
{
	int arr[] = {1, 2, 3, 4, 5};
	std::vector<int> varr(&arr[0], &arr[5]);
	std::list<int> larr(&arr[0], &arr[5]);

	Print(&arr[0], &arr[5]);
	Print(varr.begin(), varr.end());
	Print(larr.begin(), larr.end());
	return 0;
}

 

지금까지 반복자의 기본적인 기능에 대해 소개했다. 즉, 컨테이너의 한 요소를 가리키는 포인터 역할과 증감, 대입 및 비교 등을 설명했다.

 

이 글은 여기서 마치며 나머지 기능들은 다음 글에서 설명하도록 하겠다.

'C++ > C++ STL' 카테고리의 다른 글

[STL] 반복자(4) - 임의 접근 반복자  (0) 2023.08.23
[STL] 반복자(3) - 순방향, 양방향 반복자  (0) 2023.08.23
[STL] 반복자(2) - 입출력 반복자  (0) 2023.08.23
[STL] 컨테이너  (0) 2023.08.23
[STL] STL의 구조  (0) 2023.08.23

관련글 더보기