10. 힙(heap)에만 생성되거나 힙에는 만들어지지 않는
특수한 클래스를 만드는 방법
객체가 자살(delete this)를 하게 만들려면
꼭 힙에 할당되어야함
!
메모리 누수를 차단하고 싶으면
힙에 할당하지 않는것도 방법…
!
이걸 컨트롤 할려면?
11. 객체가 힙에만 생성되게 하기
힙으로 한정짓는 방법은 new이외의 방법으로 객체 생성을 금지시킴
!
생성자와 소멸자로 private로 하자…
는 너무 정도를 넘는다.
!
생성자를 public으로 소멸자만 private로 하고
진짜 소명자를 호출하는 유사 소멸자를 만들자.
16. 스마트 포인터(Smart pointer)
스마트 포인터를 쓰는 이유
- 생성(construction)과 소멸(destruction) 작업을 조절
리소스 누수 막고 초기화도 해준다.
!
- 복사(copy)와 대입(assignment) 동작을 조절
객체, 포인터 복사하던지 대입하던지 결정 가능
!
- 역참조(dereferencing) 동작을 조절
가져오는 방법도 결정 가능
17. 스마트 포인터의 생성, 대입, 소멸
생성은 가리킬 객체를 하나 준비하고,
스마트 포인터의 내부에 있는 벙어리 포인터를
그 객체의 주소로 세팅하는것으로 끝
!
!
그런데 그냥 벙어리 포인터에 포인터 복사하면
삭제될때 두번삭제되는 문제 있을수 있음
그러면 값 복사? -> 성능 저하
!
-> 복사 대입을 못하게 하면 문제 해결
!
->하지만 auto_ptr은 복사, 대입될때 소유 관계를 옮김
!
-> 그러므로 값 옮기는 것을 주의
18. 역참조(Dereferencing) 연산자 구현하기
operator*, operator-> 스마트 포인터가 가리키는 객체를 반환하는 함수
참조자를 반환해야지 객체를 반환하면 슬라이스 문제가 발생
null일때는 어쩔수 없음 예외처리 해야함
스마트 포인터가 null인지 점검하기
isNull같은 멤버 함수를 추가하는건 별로 스마트 해보이지 않음
타입변환 연산자를 void*로 바꾸면 스마트 포인터가 널이면
0을 반환하고 아니면 0이 아닌 값을 반환한다.
하지만 완전치 않음…
19. 스마트 포인터를 벙어리 포인터로 변환하기
암시적으로 타입을 변환하는 연산자를 제공하면 되지만
직접 벙어리 포인터를 조작하였다간 참조 카운팅에 필요한 정보가
조정되지 않아서 두번삭제되거나 여러 문제를 일으킨다.
-> 가능하면 하지 말자.
스마트 포인터와 상속 기반의 타입변환
상속 관계에 있어도 스마트 포인터는
변환을 못해준다.
!
암시적 타입 연산자를 만들까?
-> 템플릿의 철학과 다르다
-> 클래스 계통 구조가 깊으면
더 많은 변환 연산자 추가해야함
!
암시적 변환 연산자를 만드는
템플릿을 만들자 -> 가독성이…
20. 스마트 포인터
스마트 포인터 쓸려면 신경써야 하는 경우가 많음
널 점검이나 벙어리 포인터로의 변환,
상속 기반의 변환, 상수 객체에 대한 포인터 지원등의 상황에서는
스마트 포인터 사용을 제한해야함
!
구현도 힘들고 이해하기도 힘들고 유지보수도 힘들다
디버깅도 훨씬 힘들어 진다.
!
하지만 참조 카운팅 코드에서는 스마트 포인터를 사용하면
상당히 단순해 진다던지 다른 방법으론 구현하기 힘든 기능을
구사하는데 효과적이다.
21. 참조 카운팅(Reference Counting)
여러 개의 객체들이 똑같은 값을 가졌으면,
그 객체들로 하여금 그 값을 나타내는 하나의 데이터를 공유하게 해서
데이터의 양을 절약하는 기법
!
-힙 객체를 둘러싼 내부 정보를 유지하는 작업을 단순하게 하자
-똑같은 값을 가지고 있는 객체들이 그 중복을 놔두는 것은 낭비
하지만 소멸은?
22. 참조 횟수를 기록하고 있다가
0이되면 삭제해서 메모리 누수를 막자
!
사용 카운트(use count)라고 부르기도 함
27. 참조 카운팅 기능을 가진 기본 클래스
기존의 클래스에 상속을 받는 것으로 참조 카운트 기능을 넣자.
-기능-
참조 추가(카운트 증가)
참조 제거(카운트 감소)
참조 가능성 플래그로 플래그 조회나 비활성화
28. 참조 카운트 조작을 자동화하기
앞의 RCObject에는 참조 카운트를 저장할 수 있는 공간과
참조카운트를 조작할 수 있는 멤버 함수가 있는데
이 함수는 직접 호출해 주어야 하니 이런 호출 코드도
재사용 가능한 클래스에게 몰아줘보자.
값이 다르면 기존의 값을 저장하고
공유나 사본을 만들고
참조 제거
소멸자는 그냥 참조 제거
29. 참조 카운팅 결론
좋아 보이지만 결국 어느 상황에 적합하냐가 중요
매번 카운트를 제어하고 보관하는 비용도 추가로 들고
코드도 복잡하게 된다. -> 유지보수 헬
자기 참조형(self-referential) 혹은
원형 의존형 (circular dependency)구조 (트리 등)에서는
적용이 힘들다.
!
하지만
상대적으로 많은 객체들이 상대적으로 적은 값을 공유할 때,
어떤 객체값을 생성하거나 소멸시키는데 많은 비용이 들거나
메모리 소모가 클때 큰 효과를 발휘한다.
그리고 생성 소멸을 덜 신경써도 되어서 편하다.
!
그리고 이 조건에 만족하는지 판단하는 방법은 프로파일링