본문 바로가기
개발언어/C++

STL C++ Standard Library 튜토리얼/레퍼런스 요약(3장~5장)

by 엔돌슨 2010. 4. 23.
반응형

STL C++ Standard Library 튜토리얼/레퍼런스







3장 일반적인 개념

1. namespace std

- 사용법

1. 식별자에 대해서 명시적으로 namespace의 이름을 적어주는 방법

) std::cout << std::hex << 3.4 << std::endl;

2. using 선언문(declaration)을 사용

) using std::cout; using std::endl;

cout << std::hex << 3.4 << endl;

3. using 지시자(directive)를 사용

) using namespace std;

cout << hex << 3.4 << endl;

2. 헤더(header)파일

-. 표준 헤더 파일은 확장자을 가지지 않음 (이전방식 가능)

) #include <iostream>   #include<string>

-. C 표준의 헤더파일은 확장자를 가지지 않음

) #include <cstdlib>    #include<cstring>

3. 에러와 예외 처리

-. 스트링 클래스와 같은 강력한 에러 핸들링 지원. 에러가 있으면 예외를 던진다.

-. STL 라이브러리는 안정성 보다 속도를 우선시 하기 때문에, 논리적인 에러는 검사는 거의 하지 않고 런타임에 에러가 발생했을 경우에만 예외를 던진다.

1. 표준 예외 클래스

-. C++언어나 라이브러리에서 발행되는 모든 예외는 exception클래스를 상속받아 구현되어 있다.

1. C++ 언어를 지원하기 위한 예외들

-. 메모리 할당을 위한 전역 연산자 new 실패시 bad_alloc 예외 클래스로 던짐

-. 형 변환을 위한 연산자 dynamic_cast 실패시 bad_cast 예외 클래스로 던짐

-. 런타임시 객체에 대한 실제 타입을 알아내기 위한 연산자 typeid 실패시 bad_typeid 예외 클래스로 던짐

-. 예기치 않은 예외를 다루기 위해서 bad_exception 클래스 예외 사용.

2. C++ 표준 라이브러리를 지원하기 위한 예외들

-. 대부분 logic_error클래스에서 파생

-. 유효하지 않은 인자에 의해 발생되는 에러를 위한 invalid_argument 예외클래스

-. 최대 허용 사이즈를 넘어가는 작업을 시도시 발생되는 에러를 위한 length_error 예외 클래스

-. 인자값이 유효한 범위를 벗어나는 경우 발생되는 에러를 위한 out_of_range 예외 클래스

-. 도메인(domain)에러를 위한 domain_error 예외 클래스

3. 프로그램의 범위를 벗어나는 에러를 지원하기 위한 예외들

-. runtime_error클래스로부터 파생된 예외들은 프로그램의 범위를 벗어난, 쉽게 피할 수 없는 예외를 지원하기 위한 것.

-. 내부적인 계산중 발생하는 범위 에러: range_error

-. 산술 오버플로우: overflow_error, 산술 언더플로우: underflow_error

4. 할당자

-. 메모리를 할당하고 해제하는 특별한 객체

 

 

 

 

4장 유틸리티

1. Pairs

- <utility>헤더에 정의

- 2개의 값을 하나의 단위로 관리하기 위해서 제공 또는 두 가지의 값을 반환하고자 하는 함수에 사용

) std::pair<int, float> p;  // p.first , p.second 0으로 초기화

- make_pair() 템플릿함수는 타입을 명시적으로 선언하지 않고도 pair 값을 생성할 수 있도록 도와주는 함수

) std::pair<int, char>(42,’@’);  è  std::make_pair(42,’@’); //암시적으로도 생성

2. auto_ptr 클래스

- <memory>헤더 파일에 선언.

- 예외가 발생하였을 경우, 리소스 릭을 피하기 위해 사용되는 C++ 표준 라이브러리가 제공되는 스마트포인터의 한 종류.

-. 객체는 단 하나의 소유자(auto_ptr)만을 가질 수 있다는 것이다.

-. 멤버변수로 auto_ptr을 사용할 때는 소멸자는 생략하더라도, 복사 생성자, 할당연산자는 반드시 작성하여야 한다. (의도하지 않은 소유권의 이전을 시도하기 때문)

- 할당 연산자(=)을 통해서 초기화 할 수 없음. 생성자를 사용하여 직접적으로 초기화함.

) std::auto_ptr<ClassA> ptr1(new ClassA); // OK

) std::auto_prt<ClassA> ptr = new ClassA; // Error

) std::auto_ptr<ClassA> ptr2(ptr1); //소유권을 ptr1에서ptr2로 이전

소유권의 이전은 단순 값의 복사가 아님. 이전하기 전의 소유자는 이전이 이루어진 후 NULL 포인터를 가짐. (그전의 소유자는 소유권을 상실됨)

- 자신이 가리키는 객체에 대한 소유자로서 행동하는 포인터이다.

- 주의사항

1. 소유권을 공유할 수 없다.

2. 배열타입을 지원하지 않는다.

3. 범용스마터가 아니다.

4. 표준컨테이너 클래스와 함께 사용될 수 없다.

4.3 수치제한 (numeric_limits 템플릿 클래스)

-. 수치타입은 일반적으로 플랫폼에 종속적인 제한값을 가짐.

-. 표준 전문화는 <limit>헤더 파일에서 제공

-. 장점 1.타입 안전성 제공 2.프로그래머가 제한값을 구하는 템플릿을 작성할 수 있게 함.

) template<class T>

void MaxValuePrint()

{

std::cout<<std::numeric_limits<T>::max() << endl;  //최대유효값

}

4.4 보조함수(Auxiliary Function)

-. <algorithm>헤더에 정의.

1. 최소값과 최대값의 처리

-. 두 값이 주어졌을 때 max(최대값), min(최소값)을 반환해 줌.

-. 추가적인 인자로 함수 또는 함수객체 사용가능

2. 두 값의 교환

-. swap()함수: 두 객체의 값을 교환하기 위해서 제공되는 함수.

4.5 비교 연산자의 확장

-. <utility>헤더에 정의

-. ==, < 연산자를 rel_ops에 의해서 비교연산자 !=, >, <=, >=를 구현

4.6 <cstddef> <cstdlib>헤더파일

-. C호환 헤더파일로 공통상수, 매크로, 타입, 함수들을 정의함.

 

 

5장 표준 템플릿 라이브러리

1. STL 컴포넌트

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

-. 반복자: 컬렉션(컨테이너 또는 컨테이너 부분집합) 객체가 소유한 원소를 순회하기 위해서 사용.

-. 알고리즘: 컬렉션 객체가 소유한 원소들을 처리하기 위해서 사용.

2. 컨테이너

-. 컬렉션의 원소들을 관리한다.

3. 시퀀스 컨테이너(Sequence container) : vector, deque, list

-. 모든 원소들이 자신만의 위치를 가지고 있는 순서가 존재하는 컬렉션이다.

-. 원소의 위치는 시간과 장소에 의존적이지만 원소의 값과는 무관하다.

1. Vector

-. 자신의 원소들을 동적인 배열을 이용하여 관리

-. 램덤 액세스 지원.(인덱스를 가지고 사용자가 원하는 데이터를 액세스할 수 있는 의미)

-. 배열의 끝부분의 데이터를 추가, 삭제가 빠르다.

-. 배열의 중간삽입은 삽입위치의 원소를 모두 이동해야 하므로 느림.

)  vector<int> coll; //int 타입의 vector을 생성(빈 컬렉션 생성)

- push_back : 컨테이너에 원소를 뒤에 추가함.

- size() : 소유한 원소 개수를 반환. 모든 컨테이너에 제공

2. Deque () = “double-ended queue”

- 동적 배열에 원소들 관리.

- 램덤 액세스 지원

- 양방향에 대해서 개방형 (, 끝 양쪽으로 삽입,삭제가 빠름) 중간삽입은 원소를 밀어야 하므로 느림.

- push_front / push_back: , 뒷부분에 원소를 삽입

- pop_front / pop_back  : , 뒤의 원소를 제거

3. List

- 이중 링크드 리스트처럼 구현되어 있음. 중간 삽입,삭제 빠름(내부적으로 포인터만 변경)

- 램덤 액세스를 지원하지 않음(front(), back()만 제공, 탐색으로 느림)

- push_front / push_back: , 뒷부분에 원소를 삽입

- pop_front / pop_back  : , 뒤의 원소를 제거

-. empty(): 원소가 없을 경우 true반환 ( size() == 0과 동일)

-. front() / end() : 첫번째/끝 원소를 반환

4. String (스트링)

-. Vector의 원소가 문자라는 것만 빼고는 동일.

 

 

 

2. 연관 컨테이너: set, multiset, map, multimap

-. 모든 원소들이 정렬 기준에 의존하여 자동정렬이 되는 컬렉션이다.

-. 삽입 순서와는 무관하며 값에 의존적이다.

1. Set

- 원소가 값에 따라 정렬되는 컨테이너. 중복된 값이 없는 유일한 원소값.

* 균형바이너리 트리처럼 구현되어 검색(탐색)에 유리

2. MultiSet

- 중복이 허락되고 Set과 동일.

3. Map

- key/value를 하나의 쌍으로 취급하는 원소를 관리하는 컨테이너이다.

- 제공된 정렬기준에 따라 자신의 원소를 자동적으로 정렬하여 관리한다. (Key를 기반으로 정렬)

- 연관배열: 임의의 인덱스를 가진 배열, 인덱스로 임의의 타입을 가질 수 있는 배열.

- [] 연산자를 이용하여 원소를 삽입하는 것이 가능하다.(multimap에서는 불가능. 중복이 되기때문)

) coll[“VAT”] = 0.15; 

    - key를 직접 수정할 수 없다. 수정을 위해서는 수정하고 싶은 key를 제거하고 새로운 key와 예전 value를 가지고 있는 새로운 원소를 삽입해야 함. (반복자의 입장에서 key는 상수)

4. Multimap

- 키의 중복이 허락된다는 점을 제외하고는 map와 동일. ) 사전

5.2.3 컨테이너 어댑터: stack, queue, priority queue(우선순위를 지닌 원소를 관리하는 컨테이너)

 

5.3 반복자 (, 스마트포인터, 복잡한 자료구조를 지닌 컨테이너를 순회할 수 있는 스마트포인터)

- 컨테이너가 소유한 원소들을 순회할 수 있는 객체. (*, ++, ==, !=, = 연산자)

- -개방범위(half-open range): 시작위치는 포함되지만 종료위치는 제외된다.

- begin(): 컨테이너의 첫번째 위치를 가르키는 반복자를 반환. (첫번째 원소)

- end(): 컨테이너의 마지막 원소 다음위치.

- container::iterator: 원소들을 읽기/쓰기 모드로 순회

- container::const_iterator : 읽기 전용모드 순회

) list<char>::const_iterator pos;

    for (pos = coll.begin(); pos != coll.end(); ++pos) { //마지막 원소에 다다를 때까지(전위증가)

        cout << *pos << ' ';

    } //!= 연산자를 넘어선 증가의 경우는 어떻게 될까??

- 양방향 반복자: 증가, 감소 연산자를 이용하여 양쪽 방향(,)으로 순회할 수 있는 능력을 가지고 있음(list, set, multiset, map, multimap)

- 램덤 액세스 반복자: 양방향 반복자의 모든 특성포함. 추가적인 랜덤액세스를 수행할 수 있음(vector, deque, string클래스)

- 임의의 컨테이너를 지원하기 위한 제네릭한 코드를 작성하기 위해서는 연산자 !=를 사용.

 

5.4 알고리즘

-. 컨테이너 클래스의 멤버함수가 아니다. 대신, 반복자와 함께 동작하는 전역함수이다.

-. 모든 컨테이너에 대해서 하나의 알고리즘만 존재한다.

-. #include <algorithm> 사용

-. min_element(시작,) / max_element(시작,)

-. sort(시작,), find(시작,,찾을값): 성공=원소의 위치,실패=범위의 끝을 반환

-. reverse(시작,): 원소의 순서 반전

-. 모든 알고리즘은 반-개방 범위(half-open range)로 처리된다.

) [begin, end) 또는 [begin, end[

) copy( coll1.begin(), coll1.end(), coll2.begin() ); //첫번째 컬렉션을 두번째 컬렉션에 복사

// 소스의 출발지, 소스의 종료점, 목적지: 기록할 위치

 

5.5  반복자 어댑터 ( Iterator Adapter )

1. 삽입 반복자 (Inserter)

1. 후위삽입 반복자

-. back_inserter(container): push_back()을 사용하여 뒷부분에 추가시킴.

-. push_back()을 멤버함수로 제공하는 컨테이너만 사용.  vector, deque, list가 여기에 속함

2. 전위삽입 반복자

-. front_inserter(container): push_front()를 사용하여 앞부분에 추가시킴.

-. push_front()을 멤버함수로 제공하는 컨테이너만 사용.  deque, list가 여기에 속함

3. 일반적인 삽입 반복자

-. inserter(container,pos): insert()을 사용하여 pos위치에 삽입

2. 스트림 반복자

- 스트림에서부터 읽기와 쓰기가 가능한 반복자.

-. istream_iterator<string>(cin) :표준스트림 cin에서 읽어들이는 스트림 반복자 생성

-. istream_iterator<string>() : 입력 스트림반복자의 디폴트 생성자를 호출하여 스트림-종료-반복자 생성

-. cin으로부터 읽어지는 모든 단어이며, 이단어들은 후위-삽입-반복자의 도움으로 coll에 복사 삽입된다.

-. unique_copy, ostream_iterator<string>(cout,”\n”): 모든 원소들은 줄바꿈하여 출력.

)  copy( istream_iterator<string>(cin), istream_iterator<string>(), back_inserter(coll) );

3. 역방향 반복자

-. rbegin(), rend() //역방향 반복자 생성

) copy( coll.rbegin(), coll.rend(), ostream_iterator<int>(cout, " ") );

 

5.6 조작 알고리즘

- remove(시작, , ): 값을 가지고 있는 모든 원소를 제거한다. 새로운 끝을 보관한다.

원소는 제거되고 위치는 변경되지만 원소의 개수는 동일하다.

) list<int>::iterator end = remove(coll.begin(),coll.end(), 3);//3의 값으로 가진 원소 제거. 새로운 끝을 보관

- erase(시작, ): 제거된 원소를 삭제한다.

- distance(시작, ): 두 반복자의 위치차이를 반환함.

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

-. 조작 알고리즘을 연관 컨테이너를 사용 한다면 컴파일 타임시 에러.(연관 컨테이너에 대한 반복자는 상수값으로 선언 되어 있으므로)

-. 연관 컨테이너를 지우기 위한 멤버함수 erase()를 호출

5.6.3 알고리즘과 멤버함수

-. 멤버함수의 경우 동작하는 컨테이너가 어떤 컨테이너인지 알 수 있기 때문에 더 최적화된 구현을 사용한다. (멤버함수가 존재하면 성능을 위해 알고리즘 대신 멤버함수를 사용)

) list<int> coll; //list의 경우

coll.erase( remove(coll.begin(), coll, end(), 3), coll.end() ); //나쁜 성능 (알고리즘 사용)

coll.remove(4); // 좋은 성능 (멤버함수 사용)

5.7 사용자 정의 제네릭 함수들

- PRINT_ELEMENTS(coll, “all element: “); //모든 원소를 출력

) template <class T>

inline void PRINT_ELEMENTS(const T& coll, const char* optcstr="")

{

           typename T::const_iterator pos;

           std::cout << optcstr;

           for(pos = coll.begin(); pos != coll.end(); ++pos)

           {

                     std::cout << *pos << ' ';

           }

}

 

5.9 함수-객체

- 함수-객체란: 함수처럼 행동(괄호를 사용하여 호출할 수 있고, 인자도 전달할 수 있어야 함)하는 객체를 함수-객체 또는 functor이라 함.

- () 연산자를 정의하여 사용한다.

) AddValue(10);  //해당원소에 10을 더함.;

class AddValue {

  private:

    int theValue;    // 더해질 값

  public:

    // 더해질 값으로 초기화 된다. 복사생성자에 의해서...

    AddValue(int v) : theValue(v) {

    }

// 함수 호출 연산자를 정의

    void operator() (int& elem) const {

        elem += theValue;

    }

};     //) for_each( coll.begin(), coll.end(), AddValue(50) ); //50씩 범위에 더함

1. 함수-객체는 스마트 함수이다.

-. 다른 멤버 변수나 멤버함수를 가질 수 있다.

-. 호출하기 전에 런타임시에 초기화 할 수 있다.

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

-. 템플릿을 이용한 제네릭 프로그래밍이 가능

3. 대부분의 경우 기존의 함수보다 빠르다.

-. 템플릿은 컴파일 타임시에 자세한 정보들을 정의 하기 때문에, 최적화를 제공

5.9.2. 미리 정의된 함수-객체

-. set<int, less<int> > coll;    // < 으로 원소들을 정렬

-. set<int, greater<int> > coll; // > 으로 원소를 정렬(반대의 순서)

-. bind2nd : 알고리즘이 제공해 주는 원소, 인자를 주어진 동작을 처리한후 결과 반환

) bind2nd(less<int>(), 50);     // 50보다 작은 원소 반환

 

5.10 컨테이너 원소

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

1. 원소들이 복사 생성자에 의해서 복사되어 질 수 있어야 함. 복사된 객체는 원본과 동일해야만 한다(동일한 결과 보장) => 컨테이너에 값이 들어갈 때 복사생성자에 의해서 (해당메모리를 복사) 객체 복사에 대한 정의.

2. 원소들은 할당 연산자들에 의해서 할당되어 질 수 있어야 함. 컨테이너와 알고리즘은 기존의 값을 새로운 값으로 덮어쓰기 위해서 할당 연산자 사용.

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

- 스퀀스 컨테이너의 멤버 함수들을 위해서 디폴트 생성자는 반드시 존재해야 함.

- 동일함을 검사하기 위한 ==연산자는 반드시 정의 되어 있어야 함.

* 연관 컨테이너에 대해서는 정렬의 기준이 반드시 제공되어야만 함. (내부적으로 오버라이트되어 비교연산을 할 수있게 정의가 되어있어야 정렬기준이 반영된다는 의미.)

 

5.11 STL에서의 에러 및 예외

5.11.2 에러 핸들링

- 반복자는 유효해야 한다. 반드시 초기화함.

- 종료한 위치 다음을 가리키는 반복자는 참조하는 원소가 없다.

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

-. 범위를 나타내는 두개의 반복자는 같은 컨테이너를 참조해야함.

-. 두번째 반복자는 첫번째 반복자로부터 도달할(reachable) 수 있어야 함.

-. 하나 이상의 소스범위가 사용된다면, 두번재 또는 그 이후의 범위는 첫번째 보다 더 많은 원소를 가질 수 있어야 한다.

-. 목적지 범위는 덮어쓸 수 있도록 충분한 원소를 가지고 있어야 한다.그렇지 않다면 삽입반복자를 사용함.

5.11.2 예외처리

- 노드기반의 컨테이너(list, set, multiset, map, multimap): 모든 노드기반의 컨테이너에 대해서 노드를 구성하는 도중 실패가 있었다면, 단순히 노드는 컨테이너를 빠져나간다. 노드를 제거하는 작업은 실패할 수 없다.

- 배열 기반의 컨테이너(vector, deque): 원소가 삽입 되었을 경우 완전한 복구 능력을 가지고 있지 않기 때문에, 삽입 전에 현재 컨테이너의 모든 원소들에 대한 복사본을 가지고 있어야 한다. 그러나 push, pop 동작의 경우에는 복사본이 필요 없다. 따라서 배열기반의 컨테이너가 예외를 발생한다면 이것은 컨테이너에 아무 영향을 미치지 않는다.