항목 48 : 템플릿 메타 프로그래밍, 하지 않겠는가?

  • TMP의 장점
    1. 다른 방법으로는 까다롭거나 불가능한 일을 굉장히 쉽게 할 수 있다.
    2. C++ 컴파일 타임에 실행되므로 기존 작업을 런타임에서 컴파일 타임으로 전파할 수 있다.
  • TMP는 그 자체가 튜링 완전성을 가진다.(범용 프로그래밍 언어처럼 어떤 것이든 계산할 수 있는 능력을 갖추고 있다.)
  • TMP는 반복의미의 진정한 루프가 없어서 재귀로 루프 효과를 낸다.
    • 재귀식 템플릿 인스턴스화
  • C++ 프로그래밍에서 TMP가 실력발휘하는 예
    1. 치수 단위의 정확성 확인
    2. 행렬 연산의 최적화 - “표현식 템플릿’으로 덩치 큰 임시 객체를 없애고 루프까지 합칠 수 있음. 사용자 코드에서 문법하나 바꾸지 않고 가능하다.
    3. 맞춤식 디자인패턴 구현의 생성 - “정책 기반 설계”로 따로따로 마련된 설계상 선택을 나타내는 템플릿을 만들 수 있게 된다. -> 생성식 프로그래밍의 기초

항목 49 : new 처리자의 동작 원리를 제대로 이해하자

  • new 처리자 : 메모리 할당이 제대로 되지 못한 상황에 operator new가 예외를 던지기 전에 우선적으로 호출되는 사용자 지정 에러처리 함수
  • new 처리자가 해야 하는 동작(이 중 하나를 꼭 해야 좋은 설계)
    1. 사용할 수 있는 메모리를 더 많이 확보한다. : operator new가 시도하는 이후의 메모리 확보가 성공할 수 있도록 하자
    2. 다른 new 처리자 설치 : 현재 new 처리자가 메모리 확보를 못해도 다른 new 처리자는 가능할지도 모르므로
    3. new 처리자 설치 제거 : 즉 set_new_handler에 널 포인터를 넘긴다. 설치가 되어있지 않으면 operator new는 메모리 할당 실패시 예외를 던진다.
    4. 예외를 던진다 : bad_alloc 혹은 파생된 예외를 던진다. operator new에는 처리부가 없으므로 메모리 할당을 요청한 원래 위치로 예외를 다시 던진다.
    5. 복귀하지 않음 : 대개 abort / exit를 호출한다.
  • 할당된 객체의 클래스 타입에 따라 메모리 할당 실패 처리를 가지고 싶을 때 -> 해당 클래스의 자체 버전 set_new_handler 및 operator new를 제공하도록 만들어준다.
  • 자원 관리 클래스(RAII)로 전역 new 처리자를 관리해주게(지금 클래스의 new 처리자를 사용 후 해제하게) 만든다.
  • 다른 클래스에서도 재사용할 수 있게 ‘믹스인(mixin) 양식’ 기본 클래스를 사용한다.(다른 파생 클래스들이 한 가지의 특정 기능만을 물려받아갈 수 있도록 설계된 기본 클래스)
    • 만들어진 기본 클래스를 템플릿으로 : 파생 클래스마다 클래스 데이터의 사본이 따로 따로 존재한다.
  • 이렇게 설계된 클래스 템플릿의 효과
    1. 기본 클래스 부분은 파생 클래스들이 가져야 하는 함수를 물려준다.
    2. 템플릿 부분은 각 파생 클래스가(인스턴스화된 클래스가 되며) 멤버 데이터를 따로 가질 수 있게 한다.
  • 해당 예에서 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에서만 예외가 발생하지 않도록 보장할 뿐, 표현식에서 예외가 나오지 않게 막아준단 이야기는 아니다.