41. 템플릿 프로그래밍의 천릿길도 암시적 인터페이스와 컴파일 타임 다형성 부터.
- 클래스 및 템플릿은 모두 인터페이스와 다형성을 지원한다.
- 클래스의 경우, 인터페이스는 명시적이며 함수의 시그너처를 중심으로 구성되어 있다.
- 다형성은 프로그램 실행 중에 가상 함수를 통해 나타난다.
- 템플릿 매개변수의 경우, 인터페이스는 암시적이며 유효 표현식에 기반을 두어 구성된다.
- 다형성은 컴파일 중에 템플릿 인스턴스화와 함수 오버로딩 모호성 해결을 통해 나타난다.
42. typename의 두 가지 의미를 제대로 파악하자.
- 템플릿 매개 변수를 선언할 때의 typename은 class와 같은 용도로 사용된다.
- 중첩 의존 타입 이름을 식별하는 용도에는 반드시 typename을 사용한다.
- 단, 중첩 의존 이름이 기본 클래스 리스트에 있거나 멤버 초기화 리스트 내의 기본 클래스 식별자로 있는 경우에는 예외이다.
ex)
template<typename C>
void print2nd(const C& container)
{
C::const_iterator * x;
}
C::const_itorator가 type이라는 것은 인간인 우리만 아는 것이지, 컴파일러가 구문 분석할 때 저것을 type이라고 보지 못하기 때
문에 그냥 C::const_iterator와 x를 곱해버리는 경우가 생긴다.
이런 모호성을 해결하기 위해 반드시 저 C::const_iterator는 타입이라는 것을 알려주기 위해 앞에
typename C::const_iterator * x; 라고 해야 제대로 인식하게 된다.
43. 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아두자.
- 파생클래스 템플릿에서 기본 클래스 템플릿의 이름을 참조할 때는 this-> 를 접두사로 붙이거나 기본 클래스 한정문 using
AA<int>::ParentFunc()을 명시적으로 써주는 것으로 해결하자.
44. 매개 변수에 독립적인 코드는 템플릿으로 부터 분리시키자.
- 템플릿을 사용하면 비슷비슷한 클래스와 함수가 여러개 만들어진다. 따라서 템플릿 매개 변수에 종속되지 않은 템플릿 코드는
비대화의 원인이 된다.
- 비타입 템플릿 매개변수로 생기는 코드 비대화의 경우, 템플릿 매개변수를 함수 매개변수 혹은 클래스 데이터 멤버로 대체함으
로써, 비대화를 없앨 수 있다.
- 타입 매개변수로 생기는 코드 비대화의 경우, 동일한 이진 표현 구조를 가지고 인스턴스화되는 타입들이 한 가지 함수 구현을
공유하게 만듬으로써 비대화를 없앨 수 있다.
template<typename T, std::size_t n>
여기서 타입 매개변수는 T 비타입 템플릿 매개 변수는 n
45. 호환되는 모든 타입을 받아들이는 데는 멤버 함수 템플릿이 좋다.
- 멤버 함수 템플릿 : 어떤 클래스의 멤버 함수를 찍어내는 템플릿.
- 일반화된 복사 생성연산과 일반화된 대입 연산을 위해 멤버 템플릿을 선언했다 하더라도, 보통의 복사 생성자와 복사 대입 연산
자는 여전히 직접 선언해야 한다.
46. 타입 변환이 바람직할 경우에는 비멤버 함수를 클래스 템플릿 안에 정의 해 두자.
- 모든 매개변수에 대해 암시적 타입 변환을 지원하는 템플릿과 관계가 있는 함수를 제공하는 클래스 템플릿을 만들려고 한다면,
이런 함수는 클래스 템플릿 안에 프렌드 함수로써 정의하자.
class A
{
public :
friend const A operator*(const A& lhs, const A& rhs)
{
return (lhs.GetNumber() * rhs.GetNumber());
}
}
47. 타입에 대한 정보가 필요하다면 특성 정보 클래스를 사용하자.
- 특성 정보 클래스는 컴파일 도중에 사용할 수 있는 타입 관련 정보를 만들어 낸다.
또한 특성 정보 클래스는 템플릿 및 템플릿 특수 버전을 사용하여 구현한다.
- 함수 오버로딩 기법과 결합하여 특성 정보 클래스를 사용하면, 컴파일 타임에 결정되는 if... else 점검문을 구사 할 수 있다.
ex) 현재의 iterator가 random_access를 지원하는지 여부 판단 등
48. 템플릿 메타 프로그래밍 (TMP)를 사용해보자.
- 템플릿 메타 프로그래밍은 기존 작업을 런타임에서 컴파일 타임으로 전환하는 효과를 만들어 낸다.
따라서 TMP를 쓰면 선행 에러탐지와 높은 런타임 효율을 얻을 수 있다.
- TMP는 정택 선택의 조합에 기반하여 사용자 정의 코드를 생성하는데 사용가능하며, 또한 특정 타
입에 대해 부적절한 코드가 만들어지는 것을 막는데 쓸 수 있다.
- C++에서 TMP가 활약하는 부분은 세가지로 나눌 수 있다.
1) 차수 단위(DIMENSIONAL UNIT)의 정확성 확인.
2) 행렬 연산의 최적화.
3) 맞춤식 디자인 패턴 구현의 생성.
49. new 처리자의 동작 원리를 제대로 이해하자.
- 메모리 할당이 제대로 되지 못한 상황에 대한 반응으로 operator new가 예외를 던지기 전에 사용
자쪽에서 지정 할 수 있는 에러처리 함수를 new 처리자라고 한다.
- set_new_handler함수를 쓰면 메모리 할당 요청이 만족되지 못했을 때 호출되는 함수를 지정할 수 있다.
- 예외불가(nothrow) new는 영향력이 제한되어 있다. 메모리 할당 자체에만 적용되기 때문이다.
이후에 호출되는 생성자는 얼마든지 예외를 던질 수 있다.
50. new 및 delete를 언제 바꿔야 좋은 소리를 들을지 파악해두자.
operator new와 operator delete를 바꾸는 시기는 다음과 같다.
- 잘못된 힙 사용을 탐지하기 위해서.
- 효율을 향상 시키기 위해서. (할당 및 해제 속력 Up)
- 동적 할당 메모리의 실제 사용에 관한 통계 정보를 수집하기 위해서.
- 기본 메모리 관리자의 공간 오버헤드를 줄이기 위해서.
- 기본 할당자의 바이트 정렬 동작을 보장하기 위해서. (x86 아키텍처에서는 double이 8바이트 단위
로 정렬되어 있을 때 가장 빠르다.)
- 임의의 관계를 맺고 있는 객체들을 한군데에 나란히 모아 놓기 위해서.
- 원하는 동작을 그때 그때 수행하기 위해서.
51. new 및 delete를 작성할 때 따라야 할 기존의 관례를 잘알아두자.
- 관례적으로, operator new 함수는 메모리 할당을 반복해서 시도하는 무한 루프를 가져야 하며, 메
모리 할당 요구를 만족 시킬 수 없을 때 new 처리자를 호출해야 한다. 또한 0 바이트에 대한 대책
도 있어야 하며, 클래스 전용 버전은 자신이 할당하기로 예정된 크기보다 더 큰(틀린)메모리 블록
에 대한 요구도 처리해야 한다. operator delete 함수는 null pointer가 들어왔을 때, 아무 일도 하지
않아야 한다. 클래스 전용버전의 경우에는 예정 크기보다 더 큰 블록을 처리해야 한다.
52. 위치 지정 new를 작성한다면 위치 지정 delete도 같이 준비하자.
- operator new는 기본형이 존재하지만, 기본형과 달리 매개 변수를 추가로 받는 형태로도 선언이
가능하다. 이런 형태의 함수를 위치 지정(placement) new라고 한다. operator new 함수의 위치
지정 버전을 만들 때는 이 함수와 짝을 이루는 위치 지정 버전의 operator delete 함수가 있어야 한
다. new 및 delete의 위치 지정 버전을 선언할 때는 의도한 바도 아닌데, 이들의 표준 버전이 가려
지는 일이 생기지 않도록 주의하자.
53. 컴파일러 경고를 지나치지 말자.
- 자신의 컴파일러에서 지원하는 최고 경고 수준에도 경고 메시지를 내지 않고 컴파일 되는 코드를
만드는 쪽에 최선을 다하자.
- 컴파일러 경고에 너무 민감하게 반응하지 말자. 컴파일러마다 트집을 잡고 경고를 내는 부분들이
천차 만별이기 때문이다.
54. TR1을 포함한 표준 라이브러리 구성요소와 친구가 되자.
- TR1(1차 기술 보고서) 구성요소.
1. 스마트 포인터 : (tr1::shared_ptr, tr1::weak_ptr 등)
2. tr1::function
어떤 함수가 가진 시그너처와 호환되는 시그너처를 갖는 함수 호출성 개체
void registerCallback(std::tr1::function<std::string (int)> func);
매개 변수인 func는 int로 변환 가능한 어떤 타입도 전달받는 것이 가능하며, string 타입 혹은
string 타입으로 변환이 가능한 어떤 타입도 반환할 수 있는 그런 함수를 registerCallback 함수
에 매개변수로 설정할 수 있다.
3. tr1::bind
STL 바인더로 쓰이는 bind1st 및 bind2nd와 같은 동작에 더 많은 기능이 포함되어있는 범용 바
인더.
4. 해시 테이블(hash table)
원소가 저장되는 순서를 예측 할 수 없게 구현한 연관 컨테이너들을 말한다.
tr1::unordered_set, tr1::unordered_map 등이 있다.
5. 정규 표현식
정규 표현식 기반의 탐색과 문자열에 대한 대체 연산이 가능하며 일치되는 원소들 사이의 순회도
지원한다.
6. 투플(tuple)
기존의 pair 템플릿의 새로운 버전으로 tr1::tuple 객체는 두개 이상의 객체를 몇개라도 담을 수
있게 한다.
7. tr1::array
begin 및 end를 지원하는 STL 스러운 배열을 사용하나 동적 메모리를 사용하지 않는다.
8. tr1::mem_fn
멤버 함수 포인터를 abapt 용도에 쓸 수 있는 템플릿 mem_fun 및 mem_fun_ref에 기능을 확장한
것이다.
9. tr1::reference_wrapper
기존의 참조자가 객체처럼 행세할 수 있도록 만들어주는 템플릿 사용시 참조자를 담은 것 처럼
동작하는 컨테이너를 만들 수 있다.
(컨테이너는 객체 혹은 포인터만 담을 수 있다.)
10. 난수 발생
C에서 물려받은 rand함수보다 기능이 좋은 난수 발생 기능.
11. 특수용도의 수학함수
라게르(Laguerre)다항식, 베셀(Bessel)함수, 완전 타원 적분등 특수 용도의 수학 함수를 사용할
수 있다.
12. C99호환성 확장 기능
C99의 새로운 라이브러리를 C++로 가져올 목적으로 설계된 함수 및 템플릿 모음
13. tr1::result_of
어떤 함수 호출의 반환 타입을 추론해주는 템플릿
14. 타입 특성 정보
주어진 타입에 대한 컴파일 타임 정보를 제공하는 특성 정보 클래스 모음
tr1은 어디까지나 문서이므로 기능을 사용하려면 구현해야 한다.
tr1의 14개 구성요소중 10개는 부스트에서 무료로 공개한 라이브러리 기반으로 tr1을 사용하려면 부
스트에 라이브러리를 사용하면 된다.
55. 부스트를 늘 가까이 두자.
- 즉시 투입 가능할 정도로 품질 우수에, 오픈 소스이고 어지간한 플랫폼과 컴파일러에서 모두 돌아
가는 C++ 라이브러리이다.
- TR1의 기능을 구현한 라이브러리 뿐만 아니라 가변 크기 비트셋, 다차원 배열, 함수 객체 및 고차
프로그래밍 TMP, 수학 및 수조작 타입 안정성을 갖춘 고용체등 그외에 유용한 라이브러리가 많이
있기 때문에 필요하다고 생각할 때마다 검색해 보자.
'Basic Programming > C, C++' 카테고리의 다른 글
C++ - 2차원 배열 동적할당 (0) | 2016.03.04 |
---|---|
C++ - null pointer를 써야하는 이유 (0) | 2016.03.04 |
C++ - Effectvice C++의 55가지 테크닉 Part - 3 (0) | 2016.03.04 |
C++ - Effectvice C++의 55가지 테크닉 Part - 2 (0) | 2016.03.03 |
C++ - Effectvice C++의 55가지 테크닉 Part - 1 (0) | 2016.03.03 |