[Effective C++] 항목 48 ~ 49
항목 48 : 템플릿 메타 프로그래밍, 하지 않겠는가?
- TMP의 장점
- 다른 방법으로는 까다롭거나 불가능한 일을 굉장히 쉽게 할 수 있다.
- C++ 컴파일 타임에 실행되므로 기존 작업을 런타임에서 컴파일 타임으로 전파할 수 있다.
- TMP는 그 자체가 튜링 완전성을 가진다.(범용 프로그래밍 언어처럼 어떤 것이든 계산할 수 있는 능력을 갖추고 있다.)
- TMP는 반복의미의 진정한 루프가 없어서 재귀로 루프 효과를 낸다.
- 재귀식 템플릿 인스턴스화
- C++ 프로그래밍에서 TMP가 실력발휘하는 예
- 치수 단위의 정확성 확인
- 행렬 연산의 최적화 - “표현식 템플릿’으로 덩치 큰 임시 객체를 없애고 루프까지 합칠 수 있음. 사용자 코드에서 문법하나 바꾸지 않고 가능하다.
- 맞춤식 디자인패턴 구현의 생성 - “정책 기반 설계”로 따로따로 마련된 설계상 선택을 나타내는 템플릿을 만들 수 있게 된다. -> 생성식 프로그래밍의 기초
항목 49 : new 처리자의 동작 원리를 제대로 이해하자
- new 처리자 : 메모리 할당이 제대로 되지 못한 상황에 operator new가 예외를 던지기 전에 우선적으로 호출되는 사용자 지정 에러처리 함수
- new 처리자가 해야 하는 동작(이 중 하나를 꼭 해야 좋은 설계)
- 사용할 수 있는 메모리를 더 많이 확보한다. : operator new가 시도하는 이후의 메모리 확보가 성공할 수 있도록 하자
- 다른 new 처리자 설치 : 현재 new 처리자가 메모리 확보를 못해도 다른 new 처리자는 가능할지도 모르므로
- new 처리자 설치 제거 : 즉 set_new_handler에 널 포인터를 넘긴다. 설치가 되어있지 않으면 operator new는 메모리 할당 실패시 예외를 던진다.
- 예외를 던진다 : bad_alloc 혹은 파생된 예외를 던진다. operator new에는 처리부가 없으므로 메모리 할당을 요청한 원래 위치로 예외를 다시 던진다.
- 복귀하지 않음 : 대개 abort / exit를 호출한다.
- 할당된 객체의 클래스 타입에 따라 메모리 할당 실패 처리를 가지고 싶을 때 -> 해당 클래스의 자체 버전 set_new_handler 및 operator new를 제공하도록 만들어준다.
- 자원 관리 클래스(RAII)로 전역 new 처리자를 관리해주게(지금 클래스의 new 처리자를 사용 후 해제하게) 만든다.
- 다른 클래스에서도 재사용할 수 있게 ‘믹스인(mixin) 양식’ 기본 클래스를 사용한다.(다른 파생 클래스들이 한 가지의 특정 기능만을 물려받아갈 수 있도록 설계된 기본 클래스)
- 만들어진 기본 클래스를 템플릿으로 : 파생 클래스마다 클래스 데이터의 사본이 따로 따로 존재한다.
- 이렇게 설계된 클래스 템플릿의 효과
- 기본 클래스 부분은 파생 클래스들이 가져야 하는 함수를 물려준다.
- 템플릿 부분은 각 파생 클래스가(인스턴스화된 클래스가 되며) 멤버 데이터를 따로 가질 수 있게 한다.
- 해당 예에서 NewHandlerSupport
으로부터 Widget이 상속받는다. 헌데 NewHandlerSupport 템플릿 클래스에서는 타입 매개변수 T를 아예 사용하지 않는다. - 그냥 파생 클래스들을 구분해주는 역할이다.
- NewHandlerSupport가 인스턴스화 될 때 전달되는 T를 위한 currentHandler(멤버 데이터)의 사본을 자동으로 찍어내는 공장
-
템플릿 매개변수로 Widget을 받아 만들어진 기본 클래스로 Widget이 파생된 모습 -> 신기하게 반복되는 템플릿 패턴(CRTP)
-
1993년까지 C++은 oeprator new가 메모리 할당 실패 시 널포인터를 반환했다. 그리고 몇년 후 bad_alloc예외를 던지도록 명세가 바뀌었다.
- 예외 불가(nothrow)형태 : 널 포인터 점검 기반 코드를 버리지 않기 위해서 전통적인 ‘할당 실패 시 널 반환’으로 동작하는 대안적인 형태의 operator new도 같이 내놓았는데 이를 예외불가 형태라고 한다.
- ex) Widget &pw = new (std::nothrow)Widget;
- 예외불가를 사용할 시 주의할 점 : 할당 실패 시 널 포인터를 반환한다. 하지만 할당 성공할 시 Widget 생성자가 호출되는데 여기서는 예외가 던져진다.(즉 예외불가 new로의 제약을 전혀 받지 않는다.)
- 예외불가 new는 그때 호출되는 operator new에서만 예외가 발생하지 않도록 보장할 뿐, 표현식에서 예외가 나오지 않게 막아준단 이야기는 아니다.