어쩌다 컨테이너...........😿 어디서부터 손대야 할지 감이 안 온다. 이번 주에 살펴본 내용을 정리했다!
STL은 container, iterator, algorithm의 세 가지 라이브러리로 구성되어 있다. 간단하게 한번 살펴보자.
컨테이너는 다른 객체(원소)들를 보관하는 하나의 보관소다. STL 컨테이너는 클래스 템플릿 형태로 구현되어 있어 임의의 타입의 원소들을 위한 컨테이너를 만들 수 있다.
컨테이너는 원소들의 메모리를 관리하며, 각각의 원소에 접근할 수 있는 멤버 함수를 제공한다. ft_containers에서 내가 다루게 될 컨테이너는 크게 세 가지 종류로 나뉜다.
1. Sequence containers(순차 컨테이너)
- array
- vector
- deque(double ended queue)
- forward_list
- list
2. Container adaptors(컨테이너 어댑터)
기존 컨테이너의 인터페이스를 제한하여 만든, 기능이 제한되거나 변형된 컨테이너를 의미한다. 각각의 기초가 되는 클래스의 인터페이스를 제한하여 특정 형태의 동작만을 수행하도록 한다.
- stack(LIFO)
- queue(FIFO)
- priority_queue
3. Associative containers(연관 컨테이너)
- set
- multiset
- map
- multimap
더 구체적인 내용은 구현을 시작하면서 차차 포스팅 하도록 하겠다.
반복자(iterator)란 container 속 임의의 요소를 가리키고 있는 것을 이야기한다. 증감 연산자를 통해 순회할 수 있고, 역참조(*)를 통해 값을 참조할 수 있다.
반복자 클래스를 유도(derive)하는 기초(base) 클래스다. 반복자에서 사용되는 다른 멤버 함수들을 가지고 있지 않으며, 기본 멤버 타입만이 존재한다. 사실 반복자에서 이 멤버 타입을 직접적으로 사용하지는 않지만, iterator_traits 클래스 템플릿에서의 멤버를 선언하여 적절한 형태로 인스턴스화하는 데에 사용된다.
template <class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&>
struct iterator {
typedef T value_type; // iterator가 가리키는 요소의 타입
typedef Distance difference_type; // 두 iterator의 차이를 나타내는 타입
typedef Pointer pointer; // iterator가 가리키는 요소의 포인터를 나타내는 타입
typedef Reference reference; // iterator가 가리키는 요소의 참조자를 나타내는 타입
typedef Category iterator_category; // iterator가 속해 있는 카테고리
};
iterator_category
는 아래의 태그 중 하나이다.
iterator_traits에 대해 알기 위해서는 템플릿 부분 특수화의 개념을 알아야 한다.
💡 템플릿 부분 특수화(partial specialization)란?
템플릿에서 특정 타입에 대해서 다른 실행 처리를 하고 싶을 때 템플릿 특수화가 일어난다. 템플릿 완전 특수화는 템플릿의 매개 변수들을 전부 다 특수화하는 반면, 템플릿 부분 특수화는 여러 개의 템플릿 매개 변수 중 일부만 특수화한다.아래와 같은 템플릿 클래스가 있다고 해보자.
template <typename T1, typename T2> class MyClass { // ... };
위 템플릿의 인자 중
T2
를 정수형으로 받을 때의 경우만 특수화하고 싶다면, 아래와 같이 사용할 수 있다.template <typename T> class MyClass<T, int> { // ... };
또, 두 인자 모두 타입의 포인터로 받는 경우에 대한 특수화를 하고 싶다면 아래와 같이 쓰면 된다.
template <typename T1, typename T2> class MyClass<T1*, T2*> { // ... };
iterator_traits
는 반복자 객체의 속성을 정의하는 "반복자 특질"이라고 번역된다. 반복자와 배열의 포인터 및 포인터 상수에 대한 템플릿 특수화라고 생각하면 될 것 같다.
template <class Iterator> class iterator_traits; // generic definition
template <class T> class iterator_traits<T*>; // T* specialization
template <class T> class iterator_traits<const T*>; // const T* specialization
컨테이너에 반복자들을 가지고 여러 작업을 수행할 수 있도록 도와주는 라이브러리다. 알고리즘 라이브러리의 함수들은 크게 두 가지로 나뉜다.
template <typename Iter>
void do_something(Iter begin, Iter end);
template <typename Iter, typename Pred>
void do_something(Iter begin, Iter end, Pred pred);
전자의 경우 알고리즘을 수행할 반복자의 시작과 끝만 받지만, 후자의 경우 "특정 조건"을 추가로 받는다. 이를 서술자(predicate)라고 부르며, 여기는 보통 bool
값을 반환하는 함수 객체(functor)가 들어있다.