2014년 5월 25일 일요일

[일기] STL이란 뭔지..

Standard Template Library가 뭔지 궁금하였다.

이에, 구성 요소를 살폈다. 일곱 개의 요소가 존재한단다.

 1. Container : 자료 구조
 2. Iterator     : 반복자
 3. Algorithm  : 문제를 해결하는 일반화된 함수 템플릿
 4. Function Object : [1]과 [2]에 정책을 반영하기 위한 함수 객체.
 5. Adaptor    : 구성 요소의 인터페이스를 변경하는 요소(?).
 6. Allocator  : [1]의 메모리 할당 정책을 담음.

컨테이너는 총 여섯 가지를 제공한다. 이 여섯 가지의 컨테이너는 두 가지로 나뉜다.

 1-1. Standard Sequence Container : 원소가 삽입 순서로 저장
 1-2. Standard Associative Container : 원소가 특정 정렬 순서로 저장

[1-1]에는 vector, deque, list 가 존재하며, [1-2]에는 set, multiset, map, multimap 이 존재한다.

*string은 예외로 둔다.

컨테이너는 메모리 저장 단위에 따라서도 구분된다. 두 가지로.

 1-3. Array-based Container : 데이터 여러 개가 하나의 메모리 단위에 저장(vector, deque)
 1-4. Node-based Container : 데이터 하나를 하나의 메모리 단위에 저장(list, set, multiset, map, multimap)

특히 시퀀스 컨테이너는 다음 메서드를(멤버 함수) 공통으로 갖는다.
 push_back() 종단삽입
 pop_back()   종단제거
또한 [] 연산자가 오버로딩 되어 있어 배열처럼 특정 원소에 접근 가능.
아, 원소 갯수 반환하는 size() 멤버 함수도 존재한다.

허술한 예.

[그림 1]

반복자는 컨테이너의 원소를 순회하고 접근하는 일반화된 방법을 제공한다. 이 반복자가 컨테이너와 알고리즘이 하나로 동작하게 묶어주는 인터페이스 역할을 한다. 특징은 다음과 같은데, 포인터와 같다.

 2-1. 반복자는 컨테이너 내부의 원소를 가리키고 접근할 수 있다. '*' 연산자 사용.
 2-2. 반복자는 다음 원소로 이동하고 컨테이너의 모든 원소를 순회할 수 있다. '++', '!=', '==' 연산자 사용.

 STL에서 컨테이너 원소의 집합을 순차열(Sequence)이라 부른다. 순차열은 시작과 끝을 가지는데 반복자는 여기서 순차열의 한개 원소를 가리킨다.

 STL의 모든 컨테이너는 자신만의 반복자를 제공한다. 시작은 멤버 함수 begin()으로, 끝은 end()로 반환받을 수 있다. 주의할 점은 '끝'은 마지막 원소가 아니라는 점이다.

 원소 1을 (1)이라 표현했을 때,

 (1) (2) (3) (4) (5) ... (7) (8) (9) ... (100) (101) (102) ... (1000) (1001) (1002) ... (10000) NULL

이 저장되어 있다면, begin()은 (1)을 가리키며, end()는 (10000)이 아닌 그 뒤를 가리키고 있다.

[그림 2]

[그림 1]과 [그림 2]의 코드 결과는 다음과 동일하게 같다.

10
20
30
40
50

반복자는 다섯 범주로 나눈다.
 2-3. input iterator : 현 위치의 원소를 한 번만 읽을 수 있다
 2-4. output iterator : 현 위치의 원소를 한 번만 쓸 수 있다
 2-5. forward iterator : [2-3], [2-4] 기능에 더하여 순방향으로 이동(++)이 가능하고 재할당될 수 있다
 2-6. bidirectional iterator : [2-5] 기능에 더하여 역방향 이동(--)이 가능하다
 2-7. random access iterator : [2-6] 기능에 더하여 +, -, +=, -=. [] 연산이 가능하다

보통 [2-6]을 [1-4]가 제공하고 [2-7]은 [1-3]이 제공한다.

알고리즘은 순차열의 원소를 조사, 변경, 관리, 처리할 목적의 구성 요소를 제공하는 기능을 한다. 알고리즘은 한 쌍의 반복자([begin, end))를 필요로 하며, 대부분의 알고리즘은 순방향 반복자를 요구하지만, 몇몇 알고리즘은 임의 접근 반복자를 요구하기도 한다.

 알고리즘은 같은 기능을 수행하는 여러 가지 버전으로 오버로딩되며, 약 100 여개로 정의되었다. 알고리즘은 일곱 가지의 범주로 분류한다.

 3-1. Nonmodifying algorithms
 3-2. Modifying algorithms
 3-3. removing algorithms
 3-4. mutating algorithms
 3-5. sorting algorithms
 3-6. sorted range algorithms
 3-7. numeric algorithms

이 그것이다. 알고리즘은 매우 일반적인데, 특정 컨테이너나 타입에 종속적이지 않다는 뜻이란다.

예로 find 사용하는 경우를 보인다.

[그림 3]

  그런데, sort 알고리즘은 임의 접근 반복자를 요구하므로 [1-3]이 아니면, 적용할 수 없다.

함수 객체는 Java 언어에서 Comparator 인터페이스를 구현할 때 구현할 메서드 내부의 로직을 작성하거나, Comparable 인터페이스를 구현할 때 오버라이딩하는 CompareTo 메서드 내부의 로직을 작성할 때의 사용 동기와 목적이 동일할 때 사용할 수 있다.(종이에 손 베었다..)

 가령, sort를 적용할 때, 다음과 같이 할 수 있다.

[그림 4]


[그림 5] less 구조

[그림 6] greater 구조

 어렵지 않다.

  어댑터는 구성 요소의 인터페이스를 변경한다. 가령, vector를 stack 과 같이 사용한다거나, deque를 stack 또는 queue와 같이 사용한다거나 할 수 있다.

  어댑터 종류는 다음과 같다.

 5-1. Container Adaptor : stack, queue, priority_queue
 5-2. Iterator Adaptor     : reverse_iterator, back_insert_iterator, front_insert_iterator, insert_iterator
 5-3. Function Adaptor   : binder, negator, adaptor for pointers to functions

 이며, 진한 글씨가 각 종류별 기본 어댑터이다.

 할당기는 컨테이너의 메모리 할당 정보와 정책을 캡슐화한 STL 구성 요소라고 한다. 기본 제공하는 할당기를 사용하면 무방하므로 후에, 좀더 세련된 프로그래밍을 할 때 사용할 수도 있게 된다고 한다. 그러므로 지금 자세히 알아보지 않는다.

 결론, 언더바(_)와 소문자로 된 구분없은 변수명과 컨테이너명의 사용이 어색하며 굉장히 손에 익지 않아 불편하지만, 크게 어려울 것 같다.

댓글 없음:

댓글 쓰기