본문 바로가기
Programming/Tips(C++,C#)

Chapter 5. 표준템플릿라이브러리

by 곰네Zip 2014. 10. 24.

*이 포스팅은 개인 학습을 위해 내용을 정리한 것이 목적입니다.

 

5.1 STL컴포넌트

  1) 컨테이너 : 특정 타입의 원소들의 집합을 다루는데 사용.

  2) 반복자 : 컬렉션 객체가 소유한 원소를 순회하기 위해서 사용.

     - 컬렉션 : 컨테이너의 전부or일부 집합 다른 컨테이너 타입에 대해서도 공통의 인터페이스를 제공

  3) 알고리즘 : 컬렉션 객체가 소유한 원소들을 처리하기 위함.(검색,정렬,수정 또는 다른목적으로 사용)

    - 반복자를 사용하면 알고리즘은 단 하나만 존재하면 됨.

 - STL의 기본 개념은 데이터와 동작을 구분하는 것에 의미가있음.

 - 컨테이너클래스(데이터관리), 알고리즘(동작), 이 둘을 연결하는 반복자
       ->
모든 알고리즘이 모든종류의 컨테이너와 상호작용이 가능함

 

5.2 컨테이너

 * 컨테이너의 종류

   1) 시퀀스 컨테이너 : 원소들이 순서를 가지고 자신의 위치를 가짐

   2) 연관 컨테이너 : 모든 원소들이 정렬기준에 맞추어 자동 정렬되는 컬렉션임.

 

 5.2.1 시퀀스컨테이너

  1) Vector

    - 자신의 원소를 동적인 배열을 이용하여 관리. 랜덤엑세스 지원함.

  2) Deque

    - ,뒤 양쪽으로 증가가 가능해서 벡터와 달리 원소삽입이 빠름. 중간삽입동작은 느림. vector대비 재할

     당에서 유리

 

  3) List

    - 어느위치에서나 삽입/삭제가 빠름. 그러나 순차접근만 가능하다는 단점.

 

 5.2.2 연관컨테이너

   - 정렬기준에 따라 자동적으로 자신의 원소들을 정렬함. 일반적으로 2진트리처럼 구현되어있음.

    1) set

       원소가 가진 값에 따라 정렬됨. 같은 값을 지닌 원소들은 하나뿐임

    2) multiset

       중복을 허락하는 set

    3) map

       key/value를 한 쌍으로 가지고 있는 컨테이너. 각 원소들은 정렬 기준의 기본이 되는 키를 가지고 있으

     며, 동일한 값을 가진 키는 단 하나만 존재 가능하다.

    4) multimap

       중복을 허용하는 map.

 5.2.3 컨테이너 어댑터

   컨테이너를 바탕으로 구현한 어댑터

    1) stack : LIFO

    2) queue : FIFO

    3) priority queue 

      - 우선순위를 지닌 원소들을 관리하는 컨테이너. 프로그래머에 의해 제공되어질 수 있는 정렬 기준을 기

       반으로 함.

 

5.3 반복자

  - 컨테이너가 소유한 원소들을 순회할 수 있는 객체

  1) *연산자

   - 현재 위치의 원소를 반환

  2) ++연산자

   - 다음 원소를 가리키기 위함

  3) ==, !== 연산자

   - 두 반복자가 같은 위치를 나타내는지 확인

  4) =연산자

   - 반복자를 할당 (참조하는 원소의 위치)

 

 * 반 개방의 이점

  1) 원소를 순회하는 루프의 단순화. (!=end())

  2) 빈 범위에 대한 별다른 처리 불필요

 

 5.3.1 연관컨테이너예제

  1) 연관배열과 같은 map

     연관배열 : 인덱스로 임의의 타입을 가질 수 있는 배열. []연산자가 기존의 []연산자와는 동작이 다름.

 

 5.3.2 반복자의 카테고리

  추후 7.2에서 다룸. 단방향, 양방향, 랜덤액세스 등이 존재함

 

5.4 알고리즘

  - 컨테이너에 저장된 원소를 처리하기 위해 존재. 알고리즘은 컨테이너클래스의 멤버가 아닌 전역함수.

   든 컨테이너에 대하여 하나의 알고리즘 함수만 존재.

      -> 반복자가 공통의 인터페이스를 가지므로 가능함

 

 5.4.1 범위

   - 모든 알고리즘은 하나 이상의 범위를 처리 : 컨테이너 전체를 다룰 수 있게 함.

   - 컨테이너의 처음과 끝 범위를 지정할 수 있음. 그러나 이 경우 두 인자가 모두 유효한지 확인해야 함.

 

 5.4.2 다중범위

   - 하나 이상의 범위를 처리한다. 다중범위를 사용할 경우, 두 번째에 제공되는 범위는 처음 범위보다 최소

    한 첫 번째 제공한 범위보다는 커야한다.

  - 대상의 공간이 부족하면 resize를 이용하여 해결하면 된다. 그런데 deque는 vector와 다르게 런타임에러가 없다.

5.5 반복자 어댑터

  - 반복자는 추상적인 존재. 반복자의 인터페이스를 가지는 클래스를 작성할 수 있음

   상세 내역은 7.4에서 다시 기술

 5.5.1 삽입 반복자.

   - 타겟의 사이즈를 조정 증가하여 줌. 역할은 문자대로 inserter

   1) 후위삽입반복자

    - push_back()을 이용하여 컨테이너에 객체를 옮김

   2) 전위삽입반복자

    - push_front()을 이용. list(), deque등에서만 사용가능

   3) 일반적 삽입 반복자

    - Inserter. 일반적인 삽입 반복자의 두 번째 인자로 들어온 위치 앞에 원소를 삽입함.

 

 5.5.2 스트림반복자

   - 스트림에서의 읽기/쓰기가 가능한 반복자.

 5.5.3 역방향 반복자

   - 역순 모드로 동작. 컨테이너에서 rbegin(), rend()를 이용하여 생성가능.

 

5.6 조작 알고리즘

   - 여러 알고리즘은 타겟에 제공된 범위를 수정할 수 있다. 원소의 제거도 가능.

 5.6.1 원소의 제거

  - remove()

    주어진 범위에서 특정 원소를 제거. 원소 개수를 변경하지 못함. remove함수에서 종료시 논리적

  인 종료 반복자를 리턴하여 주므로, 해당 반복자를 사용하여 원소의 끝을 알 수 있다.

 

  - erase()

   컨테이너에서 실제로 원소를 제거할 때 사용됨.

 

  5.6.2 연관컨테이너와 조작 알고리즘

   - 연관컨테이너는 데이터 삽입시 정렬되어 들어가는데, 조작알고리즘이 사용되면, 연관컨테이너의 자동정

    렬이라는 규칙이 깨어짐. 각 컨테이너의 erase() 멤버함수를 호출하여 데이터를 제거. 해당 함수는 삭제

    되는 원소의 개수를 리턴하여줌.

 5.6.3 알고리즘과 멤버함수

   - 알고리즘의 경우 범용적이므로 성능에서는 불리. 멤버함수의 경우 해당 컨테이너에 따른 더 최적화된 구

    현을 사용할 수 있음.

5.7 사용자 제네릭함수들

  - STL은 확장 가능한 프레임워크. 따라서 사용자가 정의하는 함수, 알고리즘 사용가능. 그러나 올바른 반

     복자의 사용을 위해 컨테이너의 타입을 이용하여야만 한다.

 

5.8 알고리즘 인자로서의 함수

  - 알고리즘은 사용자가 정의한 함수도 인자로 받는 것을 허용함.

 

 5.8.1 사용예

  ex) for_each()

 void print(int elem)

 {

    cout << elem << endl;

 }

 

 int main()

 {

    …

    for_each(coll.begin(), coll.end(), print);

 }

    위와 같이 함수를 인자로 넘겨 사용할 수 있음   

 

 5.8.2 조건자 (Predicates)

   - boolean을 반환하는 함수. 단항조건자(하나의 원소값을 체크)와 이항조건자(두개의 원소 속성을 비교)

    단항 조건자는 찾을 때 유리하다.

    이항조건자는 정렬등에서 유리하다 

 

5.9 함수-객체

 5.9.1 함수-객체란?

   - 함수처럼 행동하는 객체를 의미. ()연산자를 오버로딩하여 함수처럼 사용하는 것.

 

   - 함수객체의 장점

    1) 함수 객체는 스마트함수

      - 다른 멤버 변수나 다른 멤버 함수를 가질 수 있다. , 함수객체는 상태를 가지고 있다. 런타임시에 함

       수객체를 초기화 할 수 있다.

    2) 각각의 함수객체는 자신만의 타입을 가지고 있다.

      - 기존의 함수는 함수 시그니처가 다른 경우에만 다른 타입을 가질 수 있다. 그러나 함수 객체는 시그니

       처가 동일한 경우에도 다른 타입을 가질 수 있다.

       * 함수 시그니처 : 함수 이름과 함수의 인자 목록.

 

    3) 함수 객체는 기존의 함수보다 빠르다.

      - 컴파일 타임에 자세한 정보를 정의하므로 더 좋은 최적화를 제공함.

 

 5.9.2 미리 정의된 함수객체

   - C++표준 라이브러리에 기본적으로 정의된 여러가지의 함수객체가 존재함.

     less<int> : 적은 값

     greater<int> : 큰값

     negate<int> : 부정연산 (-)

     multiplies<int>: 값 곱하기

     등 여러 함수객체가 존재함.

 

5.10 컨테이너 원소

  - 컨테이너는 소유한 원소들을 특별한 방법으로 관리함

 5.10.1 컨테이너 원소들이 갖추어야 할 사항들

   - 기본적으로 충족되어야 할 요구사항

    1) 원소들은 복사 생성자에 의해서 복사되어 질 수 있어야 한다.

      - 복사된 객체는 원본과 동일하여야 한다. 만약 객체를 복사하는데 많은 시간이 필요할 경우 컨테이너의

       레퍼런스 의미론을 사용하여 이를 피할 수 있음. (6.8에서 다룸)

    2) 원소들은 할당연산자들에 의해서 할당되어 질 수 있어야만 한다.

    3) 모든 원소들은 소멸자에 의해 파괴될 수 있어야 한다.

   

  - 추가로 원소에 대해 다음의 요구 사항도 충족해야 한다.

    1) 시퀀스 컨테이너의 멤버함수를 위해 기본생성자는 반드시 존재할 것

    2) 위 경우에 따라, 동일성 검사를 위한 ==연산자는 정의되어야 함. (특히 원소 검색시)

    3) 연관 컨테이너에 대해서는 정렬의 기준이 반드시 필요함.

 

 5.10.2 값 의미론과 레퍼런스 의미론

   - 값 의미론 : 객체의 값을 복사해서 가짐.

     레퍼런스 의미론 : 객체의 주소를 가져옴.

 

   * 값 의미론만을 지원하는 STL의 장점과 단점

    1) 장점

      - 원소를 복사하는 것은 간단함

      - 레퍼런스는 에러 발생이 쉬움. 존재하지 않는 객체에 대해 참조하지 않는다는 것을 보장해야. 또한

       순환레퍼런스에 대해서도 관리가 필요

    2) 단점

      - 원소 복사는 나쁜성능을 가져올 수 있음. 복사가 불가능할수 있음

      - 같은 객체를 여러 컨테이너에 동시에 관리하는 것이 불가능

 

   - 레퍼런스 의미론을 구현하기 위해서는 원소로서 포인터를 사용하는 것. 그러나 대상이 참조될 여부가

    불투명하므로 작업에 많은 주의가 필요.

   - 스마트포인터를 사용하는 것이 더 좋은 접근방법일 수 있음. 그러나 auto_ptr은 컨테이너원소의 기본 요

    구사항을 충족하지 못한다. 이유는, 복사나 할당 후, 원본과 복사본이 다르기 때문. 따라서 직접 스마트

    포인터를 작성해야 함. (6.8참조)

 

5.11 STL에서의 에러 및 예외

 5.11.1 에러핸들링

   - STL의 목표는 안정성보다는 성능에 있음. 따라서 에러 검사가 기본적으로 수행되지 않음.

   * STL사용에 따른 지켜야 할 요구사항

    1) 반복자는 반드시 유효해야 . vector deque에서 원소의 삽입/제거,, 메모리공간 재할당 시반복자

      가 무효화 되므로 초기화 필요함.

    2) 종료위치 다음을 가리키는 반복자는 참조하는 원소가 없으므로, *, ->연산자 사용불가

    3) 범위는 반드시 유효해야만 한다.

      - 범위를 나타내는 반복자는 반드시 같은 컨테이너를 참조할 것

      - 두 번째 반복자는 첫 번째 반복자로부터 도달할 수 있을 것.

    4) 하나 이상의 소스 범위가 사용된다면, 두 번째 또는 그 이후의 범위는 첫 번째 범위보다 더 많은 범위

      를 가져야 함

    5) 목적지 범위는 덮어쓸 수 있도록 하여야 함.

 

  5.11.2 예외처리

   - 예외처리를 위한 코드성능의 저하를 유발함. STL은 원래 안정성이 아닌 성능을 목표로 고안되었음.

       -> 트랜잭션 안정성에 대한 요구 생김.

   - C++표준 라이브러리 보장내용

      1) 모든 노드 기반의 컨테이너에 대해 노드 구성중 실패가 발생시, 노드는 컨테이너를 빠져나감그러나

         list의 경우 모든 연산에 대해 트랜잭션 안정성을 충족한다.

      2) 배열 기반의 컨테이너는 원소 삽입시 완전한 복구능력이 없다. 따라서 복구를 위해서는 복사본이 필

        요함. 그러나 push, pop의 경우 컨테이너에 영향주지 않도록 보장하여줌.

 

참조 : C++ Standard Library - A tutorial and Reference

반응형

댓글