표준 템플릿 라이브러리 (Standard Template Library, STL)
는 표준 라이브러리의 일부로서 템플릿에 기반을 둔 컨테이너
, 알고리즘
, 반복자
등을 구현한 클래스와 함수를 가리키는 용어이다. 표준 템플릿 라이브러리를 사용하면 특정한 데이터 형식이나 알고리즘에 종속되지 않고 코드의 재사용성
과 유연성
을 높일 수 있다.
C++ 표준 템플릿 라이브러리
를 왜 사용해야 하는지 묻는다면, 주저 없이 컨테이너
라고 대답할 수 있다. C++
언어를 사용하는 실제 개발 현장에서 컨테이너
를 사용하지 않는 프로젝트는 아마도 찾아보기 힘들 것이기 때문이다.
컨테이너 (container)
는 같은 타입의 여러 객체를 저장할 수 있는 묶음 단위의 데이터 구조이다. 쉽게 생각해서 단어 그대로의 의미인 컨테이너 상자 또는 마트에서 물건을 담는 쇼핑카라고 생각하면 된다.
컨테이너
의 주 역할은 데이터를 저장하고 관리하며 저장된 원소에 접근할 수 있는 멤버 함수를 제공한다.참고로
컨테이너
는 한 가지 타입의 객체들만 보관할 수 있다.
반복자 (iterator)
는 객체지향 프로그래밍에서 배열 같은 컨테이너의 내부 원소들을 순회
하는 객체이다. 반복자
는 포인터
와 비슷한 동작을 한다고 볼 수 있다.
표준 템플릿 라이브러리에서 모든 컨테이너
는 각자의 반복자
를 제공한다. 각 컨테이너의 반복자는 공통의 멤버 함수를 가지는데, 대표적으로 begin
과 end
가 있다. 반복자의 begin
과 end
함수를 사용하는 예를 살펴보자.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// vector 컨테이너 선언
vector<int> vec;
vec.push_back(0);
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
// 반복자 it 선언과 동시에 vec의 시작 위치로 초기화.
vector<int>::iterator it = vec.begin();
cout << *it << endl;
cout << *(it + 1) << endl;
cout << *(it + 2) << endl;
cout << *(it + 3) << endl;
cout << *(it + 4) << endl;
return 0;
}
실행 결과
0
1
2
3
4
begin
함수는 벡터의 첫 번째 원소에 접근할 수 있도록 위치를 반환해 준다.
반복자
는포인터(pointer)
처럼 이해하면 쉽다!
begin
함수가 반환하는 반복자 it
에 포인터처럼 역참조 연산자(*)
를 이용하면 해당 원소에 접근할 수 있다. 따라서 *it
, *(it + 1)
등의 코드는 벡터 컨테이너에 저장된 원소를 출력한다.
참고
반복자의 역참조 연산은
* 연산자 오버로딩
을 통해 마치포인터
처럼 동작하게 만든 것이다.
다음의 코드는 반복자
를 포인터
와 같은 역할로 이해하면 좋은 예이다. 반복자
에도 포인터
처럼 증감 연산자
를 사용할 수 있다.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec;
for (int i = 0; i < 5; i++) {
vec.push_back(i);
}
for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
cout << *it << endl;
}
return 0;
}
실행 결과
0
1
2
3
4
두 번째 반복문을 보면 반복자 it
를 를 선언하면서 vec.begin()
함수를 호출해 vec
의 시작 위치로 초기화한다. 그리고 vec 컨테이너
를 한 칸씩 순회하면서 원소를 출력(*it
)한다. 이때 it++
처럼 반복자에 증감 연산자
를 사용할 수 있다.
한 가지 짚고 넘어갈 것은 end()
함수가 가리키는 위치이다. end()
함수는 컨테이너에 저장된 맨 마지막 원소의 바로 다음 위치를 반환한다.
다음 그림처럼 end()
가 가리키는 반복자를 past-the-end 반복자
라고 부른다. 이는 맨 마지막 원소를 지나친 반복자라는 의미이다.
만약 컨테이너가 빈 상태라면 해당 컨테이너의
begin()
과end()
는같은 위치
를 가리킨다.
반복자
를 사용하면 어떤 컨테이너에 접근하든지 같은 방법
으로 접근
할 수 있다. 이것은 컨테이너
와 알고리즘
을 함께 사용할 수 있도록 반복자가 중간자 역할을 할 수 있다는 의미이다.
표준 템플릿 라이브러리에서 모든 컨테이너는 자신만의 반복자를 제공하는데, 컨테이너의 특성에 따라 각각의 반복자가 사용할 수 있는 연산과 함수가 다르다.
반복자
는 컨테이너에 저장된 원소에 효과적으로 접근할 수 있는 도구라고 생각할 수 있다. 배열이나 리스트와 같은 컨테이너에 저장된 원소를 한번에 하나씩 접근할ㄷ 수 있게 해주는 역할이라고 보면 된다.
반복자
의 가장 큰 장점은 컨테이너의 내부 정보를 외부에 노출시키지 않고도 원소에 접근할 수 있다는 것이다. 덕분에 컨테이너의 내부 구현 방식이 변경되더라도 코드를 수정할 필요 없이 반복자를 통해 원소에 접근할 수 있다.
반복자
는 벡터, 리스트, 큐처럼 선형 컨테이너
에 적합하지만, 특정 조건을 만족하지 않을 때는 사용하기 어려울 수도 있다. 예를 들어 뒤로 이동할 수 없는 컨테이너나 무한한 개수의 원소를 가진 컨테이너에는 반복자를 사용할 수 없다. 따라서 반복자를 사용하기 전에 컨테이너의 특성과 반복자의 제약을 꼭 고려해야 한다.