2. 템플릿은 원래
사용자가 타입에 관계없는 컨테이너를 만들어 사용할 때
타입 안정성을 부여할 수 있도록 함
(vector, list, map등)
3. 그런데 그것을 응용해 여러가지 프로그래밍이 나옴
!
일반화 프로그래밍(generic programming,
조작할 객체의 타입과 상관없이 코드를 작성하도록 하는 개념)
!
-> for_each, find, merge 등의 STL 알고리즘
!
-> 템플릿 메타프로그래밍(metaprogramming)
!
->컴파일러 내부에서 실행되고
컴파일 과정이 끝날 때 실행을 멈추는 또 하나의 프로그램
4. 템플릿 프로그래밍의 천릿길도 암시적 인터페이스와
컴파일 타임 다형성부터
w는 Widget 타입으로 선언되었기 때문에,
w는 Widget 인터페이스를 지원해야 함
이 인터페이스를 소스 코드(Widget이 선언된 .h 파일 동)에서 찾으면
이것이 어떤 형태인지를 확인할 수 있으므로 이런 인터페이스를 가리켜
명시적 인터페이스라고 함
(소스코드에 보이는 인터페이스)
!
Widget의 가상 함수에 대한 실체 호출은
w의 동적 타입을 기반으로 런타임 시에 결정됨
객체 지향 프로그램에서 중요한것
5. 템플릿과 일반화 프로그래밍에서 중요한 것
T가 여러 함수를 다 지원해야 한다.
!
이 템플릿이 제대로 컴파일되려면
몇 개의 표현식이 ‘유효(valid)’해야 하는데
이 표현식들이T가 지원해야 하는 암시적 인터페이스
6. 템플릿과 일반화 프로그래밍에서 중요한 것
w가 operator> 및 operator!= 함수를 쓸때는
템플릿의 인스턴스화가 일어남
!
컴파일 도중에 하며 어떤 템플릿 매개변수가 들어가냐에 따라
호출되는 함수가 달라져
컴파일 타임 다형성이라 함
8. C: :const_iterator인데, 템플릿 매개변수인 C에 따라 달라지는 타입
!
템플릿 내의 이름 중에 이렇게 템플릿 매개변수에 종속된 것을 가리켜
의존 이름(dependent name)이라하고
!
의존 이름이 어떤 클래스 안에 중첩되어 있는 경우(const_iterator)
이름을 중첩 의존 이름 (nested dependent name)이라고 함
9. int는 템플릿 매개변수가 어떻든 상관없는 타입 이름으로
이러한 이름은 비의존 이름(non-dependent name)이라고 함
17. 해결 방법 공통점
기본 클래스 템플릿이 이후에 어떻게 특수화되더라도
원래의 일반형 템플릿에서 제공하는 인터페이스
그대로 제공할 것이라고 컴파일러에게 약속
!
어기면 컴파일 오류
18. 템플릿은 코딩 시간 절약, 코드 중복 회피등등에 좋음
!
하지만 좋다고 맊스면 어떻게 될까???
!
코드 비대화 될 수 있다.
매개변수에 독립적인 코드는 템플릿으로부터 분리시키자
19. 그걸 막기 위해
공통성 및 가변성 분석(commonality and variability analysis)을 한다.
!
-> 다른데서 비슷한것이 사용되면
두개를 잘 비교해서 공통적인 부분을 뽑아낸다.
!
!
그런데 템플릿은 딱 봐서 중복인지 알기 힘들다.
그래서 코드 비대화를 일으킨다.
20. 매개변수로 비대화가 되었을 때
템플릿 매개변수를 함수 매개변수 혹은
클래스 데이터 멤버로 대체함으로써 비대화를 없앨 가능성도 있다.
!
동일한 이진 표현구조의 인스턴스되는 타입들이
한가지 함수 구현을 공유하게 만들면 비대화를 감소시킬수도 있다.
21. “호환되는 모든 타입”을 받아들이는 데는 멤버 함수 템플릿이 직방!
같은 템플릿을 써서 인스턴스화되지만
타입이 다른 타업의 객체로부터 원하는 객체를 만들어 주는
(즉, SrnartPtr<U>로부터 SrnartPtr<T>를 만들어내는)
생성자를 가리켜
!
일반화 복사 생성자(generalized copy constructor)라고 부른다.
!
일반화된 복사 생성 연산과 일반회된 대입 연산을 위해
멤버 템플릿을 선언했다 하더라도
보통의 복사 생성자와 복사 대입 연산자는
여전히 직접 선언해야 한다.
22. 타입 변환이 바람직할 경우에는
비멤버 함수를 클래스 템플릿 안에 정의해 두자
operator*같이 매개변수에 대해
암시적 타입 변환을 지원하는 템플릿과
관계가 있는 함수를 제공하는 클래스 템플릿을 만들려면
!
클래스 템플릿안에 프랜드 함수로서 정의해야 한다.
23. 타입에 대한 정보가 필요하다면 특성정보 클래스를 사용하자
STL의 advance라는 이름의 템플릿은
지정된 반복자를 지정 된 거리에(distance)만큼 이동시키는 것
24. istream_iterator
ostream_iterator
한방향으로만 진행되고 각각 입력, 출력전용
!
순방향 반복자(forward iterator) 입출력 동시
!
앙방향 반복자(bidirectional iterator)
뒤로도 갈 수 있음
(set, multiset, map, multimap)
!
임의 접근 반복자(random access iterator)
반복자 산술 연산(iterator arithmetic)를 추가함
반복자를 임의의 거리민큼 앞뒤로 이동
(vector, deque, string)
26. 템플릿 메타프로그래밍, 하지 않겠는가?
템플릿 메타프로그래밍 (template metaprogramming:TMP)은
컴파일 도중에 실행되는 템플릿 기반의 프로그램을
작성하는 일을 말한다.
27. 템플릿 메타 프로그래밍을 쓰면…
-까다롭거나 불가능한 일을
굉장히 쉽게 할 수 있다.
!
-기존 작업을 런타임 영역에서
컴파일 타임 영역으로 전환할 수 있다.
!
실행 코드가 작아지고, 실행 시간도 짧아지며,
메모리도 적게 잡아먹는다. (컴파일 시간은 늘어난다.)
!
재귀적이다 (함수형 언어와 친숙)
그런데 보통 알고 있는 재귀와도 틀림
재귀식 템플릿 인스턴스화(recursive template instantiation)
28. 치수 단위(예를 들면 질량, 거리, 시간 등)가 똑바로 조합되는지
컴파일 도중에 확인을 할 수 있다.
!
행렬 연산의 최적화 - 여러 행렬들의 곱을 계상을 위한 임시 행렬을
만들지 않고 메모리를 적게 먹으면서 속도를 빠르게 처리할 수 있다.
!
정책 기반 설계로 각 기능을 템플릿으로 만들고 그것들을 조합해서
하나의 패턴으로 만들어 사용할 수 있다.
TMP가 좋을 때
30. new와 delete를 내 맘대로
GC없는게 장점
불편한게 장점
수동으로 메모리 관리하는게 장점인
C++
!
스포츠카는 역시 수동?
31. new delete어느정도 알긴 하는데
멀티스레드 가면 헬터진다.
!
그리고 전 자료에서도 썼지만
배열을 담을 메모리를 할당할 때에는
operator new[] 지울때는 operator delete[]
32. new 처리자의 동작 원리를 제대로 이해하자
operator new가 메모리 할당에 실패하면
구형 컴파일러는 널을 던지거나 예외를 던진다.
!
new의 동작 과정
new가 시도하는 이후의 메모리 확보가 성공할 수 있도록
사용할 수 있는 메모리를 더 많이 확보
!
자기 몫까지 해 줄 다른 new 처리자의 존재를 알고 있으면
다른 new처리자를 설치
!
new 처리자의 설치를 제거하고
예외를 던지고
!
abort()나 exit()
33. set new handler로 실패시 호출되는 함수를 지정할 수 있다.
!
자원 관리 객체를 통한 할당에러 처리를 구현하는
이런 방식의 코드는 어느 객체나 다 비슷하게 적용되니
템플릿으로 만들어서 관리하자
!
믹스인(mixin) 양식 - 다른 파생 클래스들이
한 가지의 특정 기능만을 물려받아 갈 수 있도록 설계된 기본 클래스
!
!
신기하게 반복되는 템플릿 패턴
(curiously recurring template pattern: CRTP)
라고도 부름
35. new 및 delete를 언제 바꿔야 좋은 소리를 들을지를 파악해 두자
왜 멀쩡한 operator new와 operator delete를 바꿀까?
-잘못된 힙 사용을 탐지하기 위해
데이터 오버런, 언더런이 발생할 때 테스트 코드를 넣어
delete가 점검하여 로그를 남겨 어떤 포인터가 문제인지 파악
!
-효율 향상
기본 new, delete는 일반적인 쓰임새에 맞추어 설계된 것이여서
무난하지만 성능이 좋지는 못하다.
!
-동적 할당 메모리의 실제 사용에 관한 통계 정보를 수집하기 위해
(위랑 같은 애기??)
36. 바이트 정렬(alignment)문제
아키텍처(architecture)적으로 특정 타입의 데이터가 특정 종류의 메모리
주소를 시작 주소로 하여 저장될 것을 요구하는 경우도 있음
!
바이트 정렬 제약을 따르지 않으면 프로그램이 실행되다가
하드웨어 예외를 일으킬 수 있다.
!
인텔 x86에서 double 값을 8바이트 단위로 정렬하면
런타임 접근 속도가 훨씬 빨라진다.
!
컴파일러 중에는 메모리 관리 함수에 디버깅 및 로깅 기능을 넣어 놓고
필요에 따라 전환할 수 있도록 해 둔 것들도 있다.
!
메모리 관리 함수만을 전문적으로 다루는 상업용 제품이나
오픈소스도 있다.
37. re)new 및 delete를 언제 바꿔야 좋은 소리를 들을지를 파악해 두자
-할당 및 해제 속력을 높이기 위해
기본 할당자가 아니라 클래스 전용(class-specific) 할당자를 써서
더 빠르게 할 수 있다.(진짜 도움이 되는지 미리 프로파일링 해보자)
!
-기본 메모리 관리자의 공간 오버헤드를 줄이기 위해
기본 할당자는 느리면서 메모리도 많이 먹는다.
사용자 정의로 메모리 오버헤드를 줄일 수 있다.
!
-적당히 타협한 기본 할당자의 바이트 정렬 동작을 보장하기 위해
x86에서 double이 8바이트 정렬때 빠른데 컴파일러중에는 8로 정렬을
안해주므로 직접 정의를 하자.
38. -임의의 관계를 맺고 있는 객체들을 한 군데에 나란히 모아 놓기 위해
!
특정 자료구조 몇 개가 대개 한 번에 동시에 쓰이고 있을 때
해당 자료구조를 담을 별도의 힘을 생성함으로써
메모리에 뭉쳐있게 해서 이들이 가능한 한 적은 페이징으로
성능 향상을 꾀할 수 있다.
!
-그때그때 원하는 동작을 수행하도록 하기 위해
메모리 할당,해제를 공유메모리에 한다던지
!
보안을 위해 해제한 메모리 블록에 0을 덮어쓰는
delete를 만든다던지…
39. new 및 delete를 작성할 때 따라야 할 기존의 관례를 잘 알아두자
사실 따르기 힘든 규칙은 없지만
일부는 이해하기에 살짝 힘든게 있기 때문에,
이런 부분이 무엇인지에 대해 유념해 둘 필요가 있다.
!
operator new -> 반환값이 제대로 있어야하고
메모리 모자르면 new처리자 함수를 호출하고
크기가 없는 메모리 요청(0바이트)에 대한 대비책도 있어야 하고
예외 처리도 있어야함
!
-> 말은 쉽지만 구현은 간단하진 않다.
40. 0바이트 오면 어떻게 할래? ->1바이트 요청으로 간주하고 처리한다던지
set_new_handler 함수를 호출할때 멀티스레드 상황을 대비해서
스레드 잠금을 건다던지
할당 못하겠으면 예외를 던지던지
특정클래스에는 기본 생성자를 쓰게 한다던지등등등
!
배열에는 operator new []함수를 구현
!
delete도 마찬가지 특정 클래스에 기본 소멸자를 쓰게한다던지
null이 오면 처리를 하지 않는다 던지 등등
41. 위치지정 new를 작성한다면 위치지정 delete도 같이 준비하자
저번에도 적었지만 new delete는 따라 다녀야 하는데
예외 발생으로 delete가 안되는 경우도 발생
!
operator new, delete도 마찬가지
operator new를 만들었으면 operator delete도 꼭 만들자
!
위치 지정 new, delete를 만들때 기본형이
오버라이딩 되지 않도록 조심하자.
43. 아무리 컴파일러가 똑똑해도
제작자의 의도를 읽어내지는 못한다.
!
경고 수준을 최고로 올리고 최대한 고치도록 하자
!
근데 결국 컴파일러도 컴파일러 마다임
경고 내줘야 할것도 컴파일러마다 다르기도 하니
너무 컴파일러만 믿지만도 말자.
44. TR1을 포함한 표준 라이브러리 구성요소와 편안한 친구가 되자
-표준 템플릿 라이브러리(StandardTemplate Library: STL)
컨테이너, 반복자, 알고리즘, 함수 객체 어댑터등
!
-iostream
사용자 정의 버퍼링, 국제화 기능이 가능한 입출력을 지원
!
-국제화 지원
여러 로케일(locale)을 활성 wchar_t wstring 유니코드 사용
C++ 98의 라이브러리 주요 구성요소
45. -수치 처리 지원
복소수를 나타내는 템플릿(complex) 및
수치 배열을 나타내는 템플릿 (valarray)
!
-예외 클래스 계통
최상위 클래스인 exception 및 logic_error 및 runtlme_error 등
!
-C89의 표준 라이브러리
1989년 버전의 C에 포함된 표준 라이브러리는 전부
C++에도 들어 있다.
TR1을 포함한 표준 라이브러리 구성요소와 편안한 친구가 되자
C++ 98의 라이브러리 주요 구성요소
46. TR1 구성요소
-스마트 포인터(smart pointer) tr1::shared_ptr, tr1::weak_ptr로
참조카운팅을 해서 0일때 객체 삭제, weak는 참조 상관없이 삭제
(쓰고 바로 버리는 애한테 사용)
!
-tr1::function 어떤 함수가 가진 시그너처와 호환되는 시그너처를 갖
함수호출 성 객체(callable entity)의 표현을 가능하게 해 주는 템플릿
-> 콜백을 만들어 보자.
!
-tr1:bind 싱수 멤버 함수 및 비상수 멤버 함수에 상관없이
참조로 전달되는 매개변수에 대해서도 바인딩
!
-해시 테이블(hash table)세트, 멀티 세트, 맵, 멀티맵을 구현하는데 사용됨
!
-정규 표현식(regular expression)
47. -투플(tuple) pair 템플릿의 발전형으로 여러 객체를 한번에 담을 수 있다.
!
-tr1::array begin, end를 사용할 수 있는 배열 동적 메모리를 쓰지 않는다.
!
-tr1::mem_fn 멤버 함수 포인터를 어뎁터 용도로 쓸 수 있음
!
-tr1::reference_wrapper 기존의 참조자가 객체처럼 행세할 수 있도록
만들어 주는 템플릿
!
-rand보다 성능 좋은 난수 발생
48. !
-특수 용도의 수학 함수 라게르(Laguerr) 다항식,
베셀(Bessel) 함수, 완전 타원 적분 (complete elliptic integral) 등
!
-C99 호환성 확장 기능 C99의 새로운?!?! 라이브러리를 C++로 가져옴…
!
-타입 특성정보(type traits) 주어진 타입에 대한
컴파일 타임 정보를 제공하는 특성정보 클래스 모음
!
-tr1::result of 어떤 함수 호출의 반환 타입을 추론해 주는 템플릿
!
49. TR1 자체는 단순히 명세서일 뿐
TR1의 기능을 사용하기 위해서는 명세를 구현한 코드를 구해야 하고
TR1 구현을 구할 수 있는 자료처 중 한 군데가 바로 부스트
!
TR1의 14개 구성요소 중 10개는
부스트 라이브러리를 기반으로만들거 진것
(지금은 부스트가 다 지원 중)
-> 부스트를 쓰자
50. 부스트를 늘 여러분 가까이에
부스트 품질 좋아요
오픈소스에요
어느 플랫폼이나 컴파일에서 사용 가능해요
부스트 대세에요
!
한번 쓰세요
두번 쓰세요
부스트 쓰세요
51. 부스트 소개
-문자열 및 텍스트 처리
주요 구성요소로 타입 안전성을 갖춘 printf 비슷한 서식화 기능, 정규 표
현식 및 토큰화와 구문분석 기능
!
-컨테이너
STL 양식의 인터페이스를 제공히는 고정 크기 배열,가변 크기 비트세트,
다차원 배열 등이 포함
!
-함수 객체 및 고차(higher-order) 프로그래밍 (ex lambda)
!
-일반화 프로그래밍 특성정보(traits) 클래스
52. -템플릿 메타프로그래밍(TMP)
컴파일 타임 단정문, 부스트 MPL 라이브러리 등등
!
-수학 및 수치 조작
유리수, 4원수(guaternion) 및 8원수(octonion),
최대 공약수 및 최소 공배수, 난수
!
-정확성 유지 및 테스트
암시적 템플릿 인터페이스를 형식화 라이브러리
테스트 우선 프로그래밍을 가능하게 해 줌
!
-자료구조 타입 안전성을 갖춘 공용체(투플 등)
53. -타 언어와의 연동 지원
C++와 파이썬과의 상호운용을 가능케하는 라이브러리
!
-메모리
고성능의 고정 크기 할당지를 지원하는 풀(Pool) 라이브러리
scoped_array 스마트 포인터 등
!
-기타
CRC 점검, 날짜 및 시간 조작, 파일 시스템 횡단 둥을 지원히는
라이브러리