반응형

http://mskyt.tistory.com/54



[1장] C++ 기본
 - explicit 생성자
 - 복사생성자 (copy constructor)
 - 복사 대입 연산자 (copy assignment operator)
 - 함수 인자로 전달될 때는 복사 생성자가 불림

항목1.  C++는 언어들의 연합체
 C + 객체지향 + 템플릿 + STL

항목2. define 대신 const, enum, inline 사용
 - 매크로 대신 상수 사용
 - 문자열일 경우 const를 앞뒤로 (상수포인터)
 - 클래스 상수 static const 사용 (구현파일에 따로 정의 필요)
 - 매크로 함수대신 inline template 함수 사용

항목3. 낌새만 보이면 const
 - const char *p : 상수 데이터
 - char *const p : 상수 포인터
 - const vector::iterator   vs  vector::const_iterator
 - 상수 멤버 함수 : 해당 객체의 논리적인 상태를 바꾸지 않겠다고 약속한 함수. const가 있고 없고에 따라 오버로딩 가능 (상수객체에 대한 함수를 따로 정의)
 - 비트수준의 상수석 vs 논리적 상수성 (사용자가 알아챌수 없으면 된다) : 논리적 상수성 파악은 힘들고, mutable 키워드로 const에서도 변수 변경 가능
 - 상수함수 비상수함수 코드 중복 - 비상수 함수가 상수 함수를 호출하도록
  const 떼어내기 :  const_cast<char&>(static_cast<const T&>(*this)[position])

항목4. 객체 초기화
 - 대입과 초기화는 다르다
 - 멤버 초기화 리스트로 복사 생성자 호출
 - 상수&참조자 변수 반드시 초기화
 - 기본클래스가 파생클래스보다 먼저 초기화됨
 - 멤버변수는 초기화 리스트 순서에 상관없이 선언된 순서로 초기화
 - 정적 객체(전역객체, 네임스페이스 전역 객체, 클래스 정적 변수, 함수내 정적 변수, 파일내 정적변수)의 초기화에 주의
     - 번역 단위 : 컴파일을 통해 하나의 오브젝트 파일을 만드는데 바탕이 되는 소스코드
     - 두개이상의 번역단위에서 비지역 정적 객체의 초기화 순서는 정해지지 않음 : 싱글턴 패턴 또는 참조자 반환 함수 사용


[2장] 생성자, 소멸자, 대입 연산자
항목5. 컴파일러 자동 생성(implicit) 함수들
 - 복사생성자, 복사대입연산자, 소멸자 자동생성
 - implicit 복사생성자는 각 멤버변수 복사생성
 - implicit 복사대입연산자도 각 멤버변수 복사대입
 - 참조자는 원래 자신이 참조하던 것과 다른 객체 참조 불가능

항목6. 컴파일러 자동생성 함수 금지시키기
 - 복사생성자, 복사대입생성자를 private로 선언
 - 프렌드 클래스도 안되게 : 선언만 하고 정의는 안함
 - 컴파일타임에 막고싶다면 uncopyable 클래스를 만듬

항목7. 다형성을 가진 기본 클래스는 소멸자를 가상 소멸자로
 - 팩토리 함수로 동적 할당된 객체를 쓰면, 지울때 기본클래스 포인터로 접근되고, 비가상소멸자이면 기본클래스 소멸자가 호출됨
 - 가상함수를 하나라도 가졌으면 가상 소멸자를 사용
 - 가상함수가 C++에선 클래스에 별도 자료구조 추가됨 : 실행중에 알기위해서 vptr(가상함수테이블 포인터), vtbl(가상함수 테이블) 
 - std::string, STL 컨테이너들은 비가상 소멸자

항목8. 예외가 소멸자를 떠나지 못하도록
 - vector가 소멸되다가 두번째 원소 소멸중 예외 : 미정의 동작
 - 방법1 : catch 하여 abort를 호출
 - 방법2 : 예외무시
 - 인터페이스를 분리. 안하더라도 리소스 관리하게 만들고 로그남기기

항목9. 객체 생성, 소멸시에는 가상 함수 호출 호출하지 않는다
 - 생성, 소멸자가 실행되는 동안에는 완전히 기본클래스로 보고 동작. 가상 함수더라도 기본 클래스 함수가 실행된다.

항목10. 대입연산자는 *this의 참조자를 반환하게 하자
 - A=B=C 처럼 대입연산자가 사슬처럼 얽히도록

항목11. 대입연산시에는 자기대입에 대한 처리가 빠지지 않도록
 - 중복참조(aliasing)
 - 일치성 검사(identity test)
 - 대개 예외에 안전하게 작성하면 자기대입에도 안전해진다
 - 복사후 맞바꾸기 기법 - reference copy 후 swap, pass by value로 받고 swap

항목12. 객체의 모든 부분을 빠짐없이 복사하자
 - 모든 멤버함수와 상속한 기본 클래스 복사를 빼먹지 말라
 - 복사 생성자와 복사 대입 연산자가 코드 중복되는 듯하지만,  대입연산자에서 복사생성자 호출 또는 그 역은 불가능

[3장] 자원관리
항목13. 자원 관리에는 객체가 그만
 - 팩토리 함수 : 클래스 객체를 동적할당하고 포인터 반환 해제는 호출한 쪽에서
 - 해제하기전 return이 되거나 예외가 발생하면 해제 안됨
 - 자원해제를 소멸자가 맡도록
 - 자원 관리 객체 : 자원 획득 즉시 초기화 (RAII-Resource Acquisition Is Initialization), 소멸자로 자원 해제
 - std::auto_ptr<T> : 스마트 포인터
     - 어떤 객체를 가리키는 auto_ptr의 개수가 여러개면 큰일 : 복사 생성자 및 대입연산자에서 피연산자를 null로 바꿔버림

 - tr1::shared_ptr : 참조카운팅방식의 스마트 포인터 (RCSP)
    - 가비지 컬렉션과 유사, 순환참조에 대한 해제는 안됨
 - 스마트포인터는 동적 배열에 적용시킬 수 없다

항목14. 자원 관리 클래스의 복사 동작
 - 힙에서 생긴 자원만 관리에 적합
 - RAII 객체의 복사정책 : 복사 금지 or 참조 카운팅 수행 or 관리 자원을 deep copy or 관리자원 소유권 이전
 - tr1::shared_ptr의 경우 삭제자 지정 가능

항목15. 자원관리클래스에서 관리되는 자원은 외부에서 접근할 수 있도록
 - tr1::shared_ptr, auto_ptr은 get함수를 명시적으로 지원
 - operator* 암시적 지원 또는 operator Handle() const 암시적 변환 함수

항목16. new와 delete시에는 사용형태를 반드시 맞춰라
 - 배열을 위해 할당받는 힘메모리엔 대개 배열원소의 개수가 저장됨
 - 객체 배열을 해제할 땐 delete[] 사용

항목17. new로 생성한 객체를 스마트포인터에 저장하는 코드는 별도의 한 문장으로
 - 인자로 넘기는 경우, 다른 인자 계산도중 예외가 발생하여 자원 누출 가능
 - 변수로 만들어 놓고 넘기자


[4장] 설계 및 선언
항목18. 인터페이스 설계는 제대로 쓰기엔 쉽게. 엉터리로 쓰기엔 어렵게
 - 사용자가 저지를 만한 실수를 염두
 - 인자용으로 struct만 만들어넣어도 타입 체크가능
 - enum이나 유효값 집합을 미리 정의
 - const를 붙여 엄하게 못쓰게함
 - 인터페이스를 일관성있게 : 배열 크기 이름 (length/size/count), property/method
 - 팩토리 함수는 애초부터 스마트포인터를 반환하도록
   - 스마트포인터 처음에는 null을 가리키게 해놓고 나중에 바꾸기
   - shared_ptr<A> ret(static_cast<A*>(0), deleter)
   - 교차 dll 문제 : new가 호출된 dll과 다른 dll에 있는 delete가 호출 되었을 때 런타임 에러 - shared_ptr에서 정한 삭제자가 특정 dll에서 불림으로써 해결
 - 부스트의 shared_ptr은 크기 두 배 동적 메모리 할당. 스레드 동기화 오버헤드

항목19. 클래스 설계는 타입 설계와 똑같이 취급
클래스 설계시
 - 생성과 소멸은 어떻게
 - 객체 초기화와 대입의 차이
 - 값에 의한 전달되는 경우의 의미 (복사생성자)
 - 클래스의 invariant 제약 조건
 - 기존클래스의 상속 계통망
 - 타입 변환의 허용 (암시적, 명시적)

항목20.  값에 의한 전달보다 상수객체 참조자에 의한 전달이 낫다
 - func(const T& a)
 - 사본이 전달되고, 생성 소멸에는 꽤나 고비용을 들어갈것
 - 복사손실 : 파생클래스 객체가 기본클래스 객체로 넘어갈때 잘림
 - 참조자는 컴파일러에선 사실상 포인터로 구현됨

항목21. 함수에서 객체를 반환해야 할 경우 참조를 반환하려 들지 말자
 - 지역변수의 참조를 넘겼다간 소멸되면서 잘못됨
 - 함수내 동적할당을 받았다면 누가 delete를?
 - 값에의한 리턴을 하더라도 대부분의 컴파일러는 생성/소멸 최소화하도록 최적화됨

항목22. 데이터 멤버가 선언될 곳은 private 영역
 - public : 일관성 사라짐. 캡슐화
 - protected : 파생클래스에게 public이랑 동일

항목23. 멤버함수보다는 비멤버 비프렌드함수와 더 가까워지자
 - 멤버함수가 적을수록 캡슐화가 잘된 것. 자유도가 높음
 - 편의 함수들을 여러파일에 쪼개서, 같은 네임스페이스

항목24. 타입변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자
 - 클래서 선언 밖에 함수 선언
 - 암시적 타입 변환에 대해 매개변수가 먹혀들려면 매개변수 리스트 있어야한다
 - 퍼블릭 함수로만 가능하다면 프렌드로 안해도 됨

항목25. 예외를 던지지 않는 swap
 - 표준 swap 구현 : 복사가  3번 일어남
 - pimpl (pointer to implementation) 기법
     - 복사비용이 높은 경우 포인터만 swap 
     - template<> 완전 템플릿 특수화 - pimpl 구현을 위한 특수화
     - template<typename T> 부분 특수화
 - 인자기반탐색(쾨니그탐색?)
 - using std::swap으로 특수화된 swap 찾고, 안되면 일반 std::swap 사용
 - 일반적인 구현 : public으로 하나 만듬. 비멤버 동일 네임스페이스에 하나 만듬. std::swap 특수화 버전만듬
 - 예외를 던지면 안됨 : 컴파일러가 강력한 예외안정성을 보장으로 도움을 주려면
 
 
[5장] 구현
항목26. 변수 정의는 늦출 수 있는 데까지 늦추자
 - 생성과 호출 비용
 - 기본생성자가 불리는 비용도

항목27. 캐스팅은 절약하자
 - 4가지 캐스팅
     - const_cast : 객체의 상수성을 없애는 용도
     - dynamic_cast : 안전한 다운캐스팅. 높은 런타임 비용
     - reinterpret_cast : 하부 수준 캐스팅
     - static_cast : 암시적 변환을 강제로 진행할 때
 - 객체 하나가 어떤 클래스로 캐스팅 되느냐에 따라 포인터 오프셋이 달라짐 - 런타임에 계산됨
 - 다중상속되면 무조건. 단일상속에서도
 - dynamic_cast : 클래스 이름 문자열 비교 기반 - 차라리 기본클래스에 가상 함수를 두도록 
 - 잘 작성된 c++ 코드는 캐스팅을 거의 쓰지 않는다

항목28. 내부에서 사용하는 객체에 대한 핸들을 반환하는 코드는 되도록 피하자
 - 참조자, 포인터, 반복자는 모두 핸들
 - private 멤버변수에 대한 접근을 허용하는 셈
 - 무효참조핸들 : 바깥으로 떨어져 나간 핸들은 그 핸들이 참조하는 객체보다 더 오래 살 위험이 있음

항목29. 예외안전성이 확보되는 그날 위해 싸우고 또 싸우자

 - 자료구조 오염 방지을 목표로
 - 3가지 보장 단계
   - 기본적인 보장 : 모든 것을 유효한 상태로 유지하겠다는 보장. 객체 내부적 일관성을 유지
   - 강력한 보장 : 예외가 발생하면 프로그램 상태를 절대로 변경하지 않겠다. 원자적인 동작 보장
   - 예외불가 보장 : 예외를 절대로 던지지 않음
 - 할 수 있다면 예외불가 보장이 좋겠지만, 현실적으론 강력한 보장 또는 기본적인 보장
 - 강력한 보장 대표적인 기법 : copy and swap, pimpl 관용구 - 객체 사본 수정후 마지막에 반영 - 전부 바꾸거나 아예 안바꾸거나
 - 함수 부수 효과 : 함수내 상태를 바꾸는 함수를 부를 때 보장성이 낮아짐

항목30. 인라인 함수는 미주알고주알 따져서 이해해두자
 - 컴파일러가 문맥별 최적화
 - 목적 코드 크기가 커짐. 페이징 회수 증가. 명령어 캐시 적중률 감소
 - inline은 요청이지 명령이 아님
 - 클래스 선언에 함수를 정의하면 인라인으로
 - 인라인 함수는 헤더파일 안에 정의해주는게 좋음 - 링크 타임이 아니라 컴파일 타임에 해줘서 (템플릿도 마찬가지)
 - 복잡한 함수나 재귀함수, 가상함수 등은 컴파일러가 인라인 무시
 - 함수 포인터로 접근하면 함수 본문 생성됨
 - 생성자와 소멸자는 인라인으로 하기 애매
 - 라이브러리 개발자 입장에선 인라인은 뻔히 보일때만.함수를 바꾸면 컴파일을 다시해야함. 인라인이 아니면 링크만 다시해도됨

항목31. 파일 사이의 컴파일 의존성을 최대로 줄이자
 - C++은 인터페이스와 구현이 그리 깔끔하게 분리돼있지 않음
 - 구현세부사항(private 멤버변수)가 헤더파일 선언부에 들어있음
 - 표준라이브러리 헤더는 어지간하면 컴파일 병목이 안됨. 특히 precompiled header를 사용한다면
 - 스몰톡이나 자바는 포인터 뒤에 구현부를 숨김
 - 마찬가지로 pimpl 기법을 사용 : 핸들클래스
 - 정의부에 대한 의존성을 선언부에 대한 의존성으로 바꾸어 놓자!
    - 객체참조자, 포인터로 할 수 있다면 객체를 직접 사용하지 말자 : 객체 크기를 알아내려면 정의부를 보는 수밖에
    - 할 수 있다면 클래스 정의 대신 클래스 선언에 최대한 의존하도록 : 함수 선언시엔 클래스 정의가 필요 없음. 전방선언 하자
 - 실제로 쓰지도 않을 타입 정의에 대해 사용자가 의존성을 끌어오지 않도록
    - 선언부와 정의부에 대해 별도의 헤더파일 제공 : 헤더파일을 짝으로 관리
 - C++에선 템플릿 선언과 정의가 분리될 수 있도록 export 키워드 제공
 
- pimpl 관용구 핸들클래스와 구현클래스 멤버함수 1대1 대응
- 핸들클래스 대신 인터페이스 클래스(가상클래스) 사용 : 포인터나 참조자로 밖에 사용 못함
- 팩토리 함수나 가상 생성자 제공


[6장] 상속 그리고 객체 지향 설계
항목32. public 상속 모형은 반드시 is-a를 따르도록
 - 파생클래스 is a 기본클래스 (일종이다)
 - 정사각형 클래스는 직사각형 클래스를 상속받기 좀 그렇다. 직사각형의 모든 성질(및 허용정도)가 정사각형에 적용 되지 않을 수 있음
 
항목33. 상속된 이름을 숨기는 일은 피하자
 - 기본클래스에서 오버 로드 했더라도 파생클래스에서 오버라이딩 했으면 가려진다 - 매개변수 타입이 다르거나 말거나
 - using을 통해 명시적으로 끌어낼수 있다.
 - private 상속을 받는다면 using도 안 통함. 전달함수 만들어야 한다.

항목34. 인터페이스 상속과 구현상속의 차이
 - 순수가상함수 : 파생클래스에서 다시 선언해야. 정의가 전혀 없음
 - 단순가상함수 : 오버라이딩 가능. 기본구현 물려받음
   - default는 있지만, 오버라이딩을 권할 때 : 순수 가상함수로 해놓고 protected로 디폴트함수 구현
   - 헤더 파일에서 인라인 호출
   - 굳이 protected 함수 만들고 싶지 않다면 순수 가상함수 구현해놓고 파생클래스에서 명시적 호출
 - 비가상 함수 : 클래스 파생에 상관없이 변하지 않는 동작
   - 필수적 구현도 물려받음. 재정의하면 안됨

 - 실수1 : 모든 함수를 비가상 함수로. 특히 소멸자는 안됨
 - 실수2 : 모든 함수를 가상함수로

항목35. 가상함수대신 쓸 수 있는 것들
 - 비가상 인터페이스 관용구를 통한 템플릿 메서드 구현
    - private으로  가상함수 선언. public 비가상 함수서 가상함수 호출
    - 비가상 함수 인터페이스 : non virtual interface / template method / 가상함수 wrapper
    - 사전/사후 동작 넣게 좋음 : 뮤텍스, 로그 등
 - 함수 포인터로 구현한 전략 패턴
    - 케릭터 생성자에 체력치 계산용함수 포인터 넘김
    - typedef int (*HealthCalcFunc)(const GameCharacter& gc)
    - 같은 클래스로 다른 계산법, 런타임에 계산법 교체
    - 비공개 데이터로 접근이 불가능. 캡슐화를 약화시켜야함
 - tr1::function으로 구현한 전략패턴
    - 함수 호출성 객체
    - typdef std::tr1::function<int (const GameCharacter&)> HealthCalcFunc
    - 템플릿으로 시그니쳐를 받음
    - 인수 및 반환값의 암시적 변환을 허용
    - 함수객체 만들기 : struct HealthCaclulator { int operator()(const GameCharacter&) const; }

항목36. 상속받은 비가상 함수를 파생 클래스에서 재정의하는 것은 절대 금물
  - 비가상함수는 정적 바인딩

항목37. 상속받은 함수의 기본 매개변수 값은 재정의 금지
  - 기본 매개변수도 정적 바인딩

항목38. has-a 혹인 is-implemented-in-terms-of를 모형화할 때는 객체 합성
  - 함성(composition) - layering containment aggregation embedding
    - 응용 영역 객체간 합성 : has-a
    - 구현 영역 객체간 합성 : is implemented in terms of
  - list 자료 구조로 set을 만든다고 해도 list를 상속받으면 안됨. list를 멤버변수로 들고있어야

항목39. private 상속은 심사숙고해서 구사하자
  - 암시적 타입 변환 안됨
  - 기본클래스로 부터 상속받은 것들이 private로
  - 구현만 물려받고 인터페이스는 물려받지 않는다.
  - 객체 합성으로 대체할 수는 있음
  - 파생클래스가 기본클래스의 비공개 부분에 접근시 or 가상함수 하나이상 재정의 할 때
  - 공백기본클래스 최적화 : unary_function, binary_function
  - is-a 관계가 아닌데 protected 멤버변수에 접근하고 플때

항목40. 다중 상속은 심사숙고 사용
  - 두 기본클래스에서 같은 이름을 사용할 경우 모호성이 생김
    - mp.BorrowableItem::checkOut() 같이 사용해야 
  - 마름모꼴 상속
    - 데이터 중복 상속을 막으려면 가상 상속을 해야함
    -  basic_ios, basic_istream, basic_ostream, basic_iostream이 마름모꼴 상속 클래스 템플릿
    - 가상상속시, 파생클래스에서 가상 기본 클래스를 초기화할 때 가상 기본클래스의 거리에 상관없이 초기화를 책임져야함
    - 웬만하면 쓰지 말고, 쓰더라도 데이터 최소화
  - 객체합성을 쓰고싶지만 가상클래스라서 데이터로 못들고 있을 때 - public으로 기본 클래스 상속. private로 객체합성용 클래스 합성


[7장] 템플릿과 일반화 프로그래밍
 타입 안정성을 위해 도입
 일반화 프로그래밍이 발전하면서 템플릿 메타프로그래밍이 탄생

항목41장. 암시적 인터페이스와 컴파일 타임 다형성
 - 객체지향 : 명시적 인터페이스 explicit interface, 런타임 다형성 runtime polymorphism
 - 템플릿 : 암시적 인터페이스implicit interface, 컴파일 타임 인터페이스 compile time interface
 - 제대로 컴파일 되기 위한 인터페이스
   - 명시적 인터페이스 : 함수시그니쳐 기반
   - 암시적 인터페이스 : 유효 표현식

항목42. typename의 두가지 의미
 - template<class T> class Widget,  template<typename T> class Widget - 완전히 똑같은 구문
 - 의존이름 : 템플릿 매개변수에 종속된 경우
    -  C::const_iterator *x : C가 뭔지 모르는 이상, const_iterator가 정적 클래스 변수로 인쇡되어 x와 곱하기 하는 구문으로 인식 될 수도
    - c++에선 중첩 의존 이름을 만나면 기본적으로 타입이 아닌것으로 간주
    - typename C::const_iterator iter 이런식으로 해야 정확
    - 중첩의존타입이름이 기본클래스 리스트에 있거나, 멤버 초기화 리스트내의 기본 클래스 식별자로 있을 땐 typename 안붙임

 - iterator 템플릿에서 일반적으로
   - typedef typename std::iterator_traits<iterT>::value_type value_type;
   - iterator가 가르키는 자료 타입을 의미

항목43. 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법
 - 파생 클래스가 인스턴스화 될때까지 템플릿 매개 변수를 모르기 때문에 기본클래스의 멤버함수가 뭔지모름 :  템플릿 특수화 버전이 있을 수 있어서.
   - template<> class MsgSender<CompanyZ> {} :  MsgSender 템플릿 매개변수가 CompanyZ일때 버젼
 - 객체지향에서 템플릿으로 가면서 상속개념 사라짐
   - 기본클래스 호출시 this->
   - using MsgSender<Company>::sendClear
   - MsgSender<Company>::sendClear
   - 명시적 한정을 하면 가상함수인 경우 좋지 않다. C++의 이른 진단 때문에 생긴 현상

항목44. 매개변수에 독립적인 코드는 템플릿으로부터 분리시키자
 - 템플릿을 남용하면 바이너리를 만들때 코드 비대화
 - 사이즈같은 비타입 매개변수를 템플릿으로 쓰는 경우 크기별로 바이너리가 생성됨 - boost::scoped_array<T> 
 - 행렬같은거 사이즈를 템플릿으로 만들면 사이즈가 상수로 전파되서 최적화가 잘됨
 - vector<int>, vector<long>은 동일

항목45. 호환되는 모든 타입을 받아들이는데는 멤버 함수 템프릿을
 - 템플릿을 사용하는 스마트포인터를 만들경우, 파생클래스->기본클래스로, const 포인터로의 변환등 암시적 변환 제공 까다로움
   - 멤버함수 템플릿 사용하여 일반화 복사 생성자 사용
   - get() 메서드를 사용하여 초기화하면 암시적 변환이 가능할 때만 컴파일됨
 - tr1::shared_pointer의 경우 포인터 타입 암시적 변환은 허용하나, 명시적으로 auto_ptr등에서의 변환은 컨트롤

항목46. 타입 변환이 바람직할 경우에는 비멤버 함수를 클래스 템플릿 안에 정의
 - 템플릿 인자 추론 과정에선 암시적 타입 변환 고려 안됨
 - friend 함수로 템플릿 없이 클래스 안에 정의
 - 함수템플릿이 아니라 함수가 선언되면 암시적 형변환이 적용가능
 - 클래스안에 비멤버함수를 선언하는 유일한 방법이 프렌드

항목47. 타입에대한 정보가 필요하다면 특성정보 클래스를 사용하자
 - STL 반복자 지원연산에 의한 분류
    - 입력반복자 : 한칸씩 전진. 한번만 읽음
    - 출력반복자 : 한칸씩 전진. 한번만 씀
    - 순방향 반복자 : 한칸씩 전진. 여러번 읽고 쓸수 있음
    - 양방향 반복자 : 한칸씩 앞뒤로 set, multiset, map, multimap
    - 임의접근반복자 : 임의칸 앞뒤로, vector, deque, string
 - 템플렛을 사용하되 반복자 특성에 따라 구현을 달리하고 플때 : 특성정보 traits을 사용
 - 해당 특성정보를 템플릿 및 그 템플릿의 특수화 버전에
 - 관용적으로 특성정보는 구조체로 구현
 - 각 자료구조별로 typedef xx_iterator_Tag iterator_category; 가 공통적으로 선언됨
 - 포인터 타입의 반복자 지원을 위해 부분 템플릿특수화 사용
 - if 문을 사용할수 있지만, 작업자 worker 함수를 오버로드하여 컴파일 타임에 동작 코드가 결정되도록
 - tr1 타입관련정보를 제공하는 특성정보 클래스가 추가됨

항목48. 템플릿 메타프로그래밍
 - 기존 런타임 작업영역을 컴파일 타임영역으로
 - 부스트의 MPL
 - TMP의 루프는 재귀함수호출이 아닌 재귀식 템플릿 인스턴스화
 - return대신 enum값으로
 - 컴파일 타임에 루프코드가 생성되었다가 최적화되면서 사라짐
 - 치수단위 정확성 확인 : 거리를 시간으로 나누는 변수에 속도값 대응
 - 행렬연산의 최적화
 - 맞춤식 디자인 패턴 구현의 생성


[8장] new와 delete를 내 맘대로
- 객체 배열 할당/해제 operator new[], operator delete[]

항목49. new 처리자와 동작 원리를 제대로 이해하자
 - 표준라이브러리로 new 처리자 설치 : set_memory_handler : new에서 예외발생시키기 전에 호출
 - 클래스별로 처리자 설정
   - static std:new_handler set_new_handler(std::new_handler p) throw();  이전 처리자 리턴
   - static void* operator new(std::size_t size) throw(std::bad_alloc);
   - static std::new_handler currentHandler; 정적변수 선언
   - new operator에서 이전 처리자 정했다가 잠시 설치했다가 해제 (RAII를 사용하면 좋음)
 - 믹스인 양식의 템플릿 클래스
   - 하위클래스는 자기자신을 템플렛 변수로 (CRTP-curiously recurring template pattern). 자기자신만을 위한 템플릿 클래스를 상속받음
 - bad_alloc이 안나고 널이 나오도록
  - new (std::nothrow) Widget 
  - 생성자에서 예외가 나올수는 있음
  - new operator에 std::nothrow를 인자로 넘기는 것

항목50. new 및 delete를 언제 바꿔야 좋은 소리를 들을지 파악해두자
 - custom new, delete operator의 구현
 - 사용 목적
   - 잘못된 힙사용 탐지 : 메모리 앞뒤로 바이트 생성. 데이터 오버런/언더럼 검사
   - 효율상승 : 메모리 사용 패텅에 특화되도록
   - 통계정보수집 : 생성 소멸 통계
   - 기본메모리 관리자 공간 오버헤드를 줄이기 위해 
   - 기본할당자 바이트 정렬보장하기 위해
   - 메모리 군집화를 위해 : 해당 자료구조를 담을 힙을 별도 생성. 페이지 폴트 가능성 최소화
   - 공유 메모리상 할당 해제
 - 바이트 정렬
   - operator new 함수는 어떠한 타입에도 바이트 정렬을 만족시키는 포인터 라야
   - malloc 함수는 만족
   - 굉장히 어렵기 때문에 왠만하면 그냥 사용. 컴파일러에서 디버깅 제공하기도.
   - 메모리 관리용 상용 툴도 잇음
   - 부스트 풀Pool 라이브러리도 좋다

항목51. new 및 delete를 작성할 때 따라야할 기존의 관례를 잘알아두자
 - 메모리 할당이 가능하면 포인터 주소 리턴. 못하면 bad_alloc 예외 발생
 - 0바이트를 요구해도 1바이트 요구로 간주
 - new 처리를 호출
 - while 문으로 메모리 할당 계속 시도
 - sizeof(X) 만큼이 인자로 전달됨
 - 상속되면서 new 함수가 오버라이드 되지 않으면, 상위 클래스 것이 불림 -> 사이즈 비교해서 다르면 표준 할당자로
 - delete : 널포인터에 대해 호출할 때 안전해야

항목52. 위치지정 new 작성하면 위치지정 delete도 같이

 - 생성자에서 예외가 발생하면 메모리를 해제해줄 수가 없어서 C++ 런타임 시스템이 맡음
 - new-delete 페어를 맞춰줘야
 - 위치지정 new : 할당해줄 주소를 인자로 받음. <new> 표준 라이브리에 있음. vector에서도 사용
 - C++ 런타임 시스템이 new와 같은 시그니쳐의 delete 콜
 - 표준 형태들
    - void* operator new(std::size_t) throw(std::bad_alloc);  기본형
    - void* operator new(std::size_t, void *) throw();  위치지정
    - void* operator new(std::size_t, const std::nothrow_t&) throw();  예외불가
 - 어떤 형태든 new가 선언되면 표준형 다 가려짐
 - 표준형들 몰아놓은 기본클래스 만들고, using xxx::operator new; 로 표준형들을 사용할 수 있도록


[9장] 그 밖의 이야기
항목53. 컴파일러 경고를 지나치지 말자
 - 일단 경고를 없애는게 좋다. 최소한 경고가 의미하는 바를 정확히 알자
 - 컴파일러마다 경고가 다를 수도

항목54. TR1을 포함한 표준 라이브러리 구성 요소와 편안한 친구가 되자
 - 현재 표준 : c++98, 차기 표준 : c++0x, tr1 : Technical Report 1
 - C++98 특징
   - STL
   - iostream
   - locale, wchar_t, wstring
   - 복소수, 수치 처리
   - 예외 클래스 계통
 - TR1
   - 스마트포인터 : std::tr1::shared_ptr, weak_ptr (순환구조일때 처리)
   - tr1::function : 시그니처가 호환되는, 함수 호출성 개체(callable entity) 표현
        tr1::function <std::string (int)> func. 인자가 int로 반환값이 string으로 변환가능한 함수
   - tr1::bind 인자 바인드
   - 해시 기반 컨테이너 : unordered_..
   - 정규표현식
   - 튜플
   - tr1::array : 정적 배열 STL
   - reference_wrapper : 참조자가 객체처럼 사용되도록
   - 우수한 난수 발생기
   - 특수 용도 수학 방정식
   - 타입 특성 정보 trait : 기본제공 타입인지, 암시적 변환이 가능한지 등
   - result_of  함수 호출의 반환 타입 추론

항목55. 부스트
 - 공개 동료 심사 방식 오픈소스 라이브러리
 - 변환 : numeric_cast, lexical_cast
 - 문자열 텍스트 처리
 - 컨테이너
 - 함수객체, 고차 프로그래밍 람다함수
 - 일반화 프로그래밍
 - 템플릿 메타프로그래밍
 - 수학 및 수치 조작
 - 정확성 유지, 테스트
 - 타언어 운용 지원 (python)
 - 메모리
 - 기타 : CRC, 날짜 시간, 파일 시스템 등
 

반응형

+ Recent posts