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로 바꿔버림
- 가비지 컬렉션과 유사, 순환참조에 대한 해제는 안됨
- 스마트포인터는 동적 배열에 적용시킬 수 없다
항목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에서 불림으로써 해결
항목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 : 객체의 상수성을 없애는 용도
- 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++에선 중첩 의존 이름을 만나면 기본적으로 타입이 아닌것으로 간주
- 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); 기본형
- 어떤 형태든 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, 날짜 시간, 파일 시스템 등
'프로그래밍(Programming) > c++, 11, 14 , 17, 20' 카테고리의 다른 글
에러코드 문자열로 변환 : FormatMessage (0) | 2013.03.07 |
---|---|
추상클래스를 상속받을때 자식에선 모든함수를 정의하는것이 좋다 (0) | 2013.03.07 |
Pure Virtual Destructor (순수 가상 소멸자) (0) | 2013.03.01 |
operator [] 를 정의하지 않고 사용하기 (0) | 2013.02.27 |
rand() 함수에 대해서... (0) | 2013.02.01 |