SlideShare a Scribd company logo
항목 25 : 생성자 함수와 비멤버 함수를 가상함수처럼 만드는 방법
상속 관계에 있는 객체의 생성 타입을 런타임에 결정해서 작동하게 하고 싶을 때 사용한다.
흔히 사용하는 것은 가상 복사 생성자라는 경우이다.
기본 클래스에 복사 생성을 하는 함수를 순수 가상 함수로 만들고, 파생 클래스에서 이 함수를 구현할 때
파생 클래스 본인을 복사 생성해서 반환하는 방식으로 구현한다.
비멤버 함수를 가상함수처럼 동작하게 할 때는
기본 클래스는 원하는 함수를 순수 가상함수로 만들고, 파생 클래스들은 이 함수를 자신의 클래스 맞게 구현한다.
그리고 클래스 외부에 기본 클래스를 인자로 받는 함수를 하나 만들고 내부에서는 그 클래스의 순수 가상 함수를 호출하도록 한다.
그러면 비멤버 함수에 파생 클래스를 인자로 넣어서 호출하면, 파생 클래스가 구현한 멤버 함수가 호출되어서
비멤버 함수를 가상함수처럼 사용할 수 있게 된다.
항목 26 : 클래스 인스턴스의 개수를 의도대로 제한하는 방법
객체를 전혀 생성하지 못하게 하려면
생성자를 private에 둔다.
객체를 하나만 생성하게 하려면
생성자를 private에 두고 전역에서 이 함수를 호출하는 함수를 프렌드로 등록한다.
그리고 이 전역함수는 해당 객체를 static으로 만들어서 반환한다.
결국 이 객체의 생성자를 호출할 수 있는 것은 전역 함수 하나 뿐이고, 이 전역함수는 해당 객체를 static으로 선언해서 사용하므로
딱 하나만 만들어지게 된다. 참고로 이 static 객체가 생성되는 것은 최초로 이 함수가 불릴 때이다. 만약 static 객체를 해당 객체 안에
담아두고 사용할 경우 이 static 객체는 사용여부와 상관없이 항상 메모리에 생성되고, 다른 static 객체들 사이에 생성되는 순서가
명확히 보장되지 않는다는 단점을 가지게 된다.
객체가 생성되는 수를 제한하고 싶을 때
고려해야 할 상황은 객체 생성이 일반적으로 프로그래머가 명시적으로 생성하는 것이 아니라
파생된 객체의 기본 클래스 부분으로 생성될 때와 다른 객체의 클래스 멤버로 생성될 때이다.
이 경우에도 생성자를 private로 둠으로써 문제를 해결할 수 있다. 즉 상속되거나 클래스 멤버가 될 수 없도록 하는 것이다.
대신 이 경우에는 항상 생성 결과가 포인터로 반환되므로 객체를 생성한 쪽에서 해제를 해주어야 한다.
스마트 포인터를 이용해서 이 부분을 쉽게 관리할 수도 있다.
객체의 수를 관리하는 것은 멤버로 객체의 수를 기록하는 static 변수를 둠으로써 가능하다.
객체가 생성되는 경우가 명시적으로 생성하는 것으로 제한하기 위해서 복사 생성등도 private로 두고, 생성자를 호출할 때
이 static 변수의 수를 확인해서 생성을 결정하도록 하는 것이다.
객체 수를 제한하는 기능이 필요한 클래스가 많을 때는 이 기능을 기본 클래스로 만들고, 이를 상속하게 함으로써 사용할 수 있다.
구현 방법은 생성 및 소멸자를 protected로 두어서 상속 받은 클래스들만 접근 할 수 있게 하고,
이 생성자에서 앞에서 언급한 객체의 수를 확인하는 로직을 둔다.
파생 클래스를 이 기본 클래스를 private 상속하고,
기본 클래스의 요소들 중 필요한 것들은 using 선언을 통해서 사용할 수 있게 등록한다.
파생 클래스가 생성되면 기본 클래스의 생성자가 먼저 호출되므로 파생 클래스에서는 개수를 확인하는 로직을 둘 필요없이
기본 클래스 생성 단계에서 객체 수를 제한하는 로직이 적용되어 작업이 진행된다.
항목 27 : 힙에만 생성되거나 힙에는 만들어지지 않는 특수한 클래스를 만드는 방법
객체가 힙에만 생성되게 하기
소멸자만 private로 둔다.
핵심은 new로만 생성하게 하고 암시적으로 객체를 생성 소멸을 하지 못하게 하는 것이다.
생성자를 private로 두지 않는 것은 그 경우에는 복사 생성자 및 기본 생성자를 고려해야 하므로 귀찮다.
어떤 객체가 힙에 생성되었는지, 그렇지 않은지를 알아내는 방법
한 가지 방법은 new 호출을 통해 생성되는 메모리 주소를 기록하고, 이와 대조를 통해 알아내는 것이다.
하지만 전역 new를 오버라이딩 한다는 부담과 메모리 주소를 하나하나 대조를 하는 비용이 크다는 단점과
다중 상속 및 가상 상속을 통해 생성된 객체에서는 제대로 작동하지 않는다는 문제를 가지고 있다.
그래서 추상 믹스인 기본 클래스라는 것을 만들어서 이를 상속해서 사용함으로써 문제를 해결한다.
다중 상속과 가상 상속의 문제는 객체의 주소가 여러 개라는 점이다. 이때 dynamic_cast를 사용하면 추상 믹스인 기본 클래스를
상속 받은 파생 클래스의 주소로 변환할 수 있게 되고, 이는 new 호출을 통해 생성할 때 사용한 주소와 같으므로
앞에서 발생한 문제를 해결할 수 있다.
객체가 힙에만 생성되지 않게 하기
객체가 힙에 생성되는 것은 operator new를 통해서만 가능하므로 이를 private로 두는 것으로 해결 가능하다.
항목 28 : 스마트 포인터
스마트 포인터의 생성, 대입, 소멸
스마트 포인터는 포인터 객체가 소멸되면 실제 내부에서 가리키고 있던 객체를 삭제한다.
문제는 스마트 포인터를 복사하면 해당 객체를 두 번 삭제할 수 있다.
이 문제를 막기 위해서 실재 객체를 생성 복사하거나 복사 대입을 막을 수도 있지만 소유권을 이전하는 방법도 가능하다.
이 방식은 복사 대입이 일어날 때 원래 있던 스마트 포인터를 삭제한다. 결국 실제 객체를 가리키는 스마트 포인터는
복사 대입된 것 하나만 유지된다. 하지만 원래 있던 스마트 포인터는 nullptr를 가리키고 있으므로 사용상 주의가 필요하다.
역참조 연산자 구현하기
스마트 포인터 내부에서 가리키는 실제 대상 객체가 nullptr인지 아닌지 확인해서 대상 객체의 참조자를 반환하면 된다.
스마트 포인터가 nullptr인지 점검
이를 확인하는 함수가 있어도 되지만 스마트 포인터를 일반 포인터처럼 사용할 수 없게 된다.
operator!를 오버로딩해서 스마트 포인터가 nullptr인 경우에만 true를 반환하게 함으로써 이 부분을 해결할 수 있다.
스마트 포인터를 벙어리 포인터로 변환하기
스마트 포인터를 일반 포인터로 변환하기 위해 암시적 변환을 사용하면 발생하는 문제가 많으므로 변환하지 말자
스마트 포인터와 상속 기반의 타입변환
멤버 함수 템플릿을 만들어 두는 것으로 가능하다. 하지만 이 변환은 스마트 포인터가 가리키는 객체의 상속 구조와는
상관없이 작동하므로 실제 포인터를 캐스팅하는 것과 같을 수는 없다.
스마트 포인터와 const
상수 객체와 비상수 객체의 관계를 보면 상수 객체가 할 수 있는 비상수 객체가 모두 다 할 수 있고,
상수 객체가 못하는 일도 비상수 객체는 할 수 있다는 특징을 이용해서 상속관계를 이용해서 만든다.
상속 스마트 포인터를 만들고 멤버에 union을 이용해서 가리키고자 하는 대상 객체를 가리키는 포인터를
상수 버전과 비상수 버전 모두 넣어둔다. 그리고 비상수 스마트 포인터를 이 상수 스마트 포인터를 상속받아서 구현한다.
항목 29 : 참조 카운팅
참조 카운팅은 기본적으로 같은 값을 가지는 객체를 가리킬 때 각각 생성하지 말고 하나를 만들어서 공유하는 것이다.
그리고 공유 참조 수를 체크해서 참조 수가 0이 되면 해당 객체를 삭제한다.
주의할 점은 대상을 수정하면 참조하는 모든 객체들이 변경되므로 수정할 때는 복사해서 새로운 객체를 만들어서 참조하게 한다.
이런 조건들을 만족하게 하려면 복잡한 코드들이 필요해진다.
그래서 이를 쉽게 구현하기 위해서는 참조 기능을 갖는 기본 클래스의 상속과 스마트 포인터를 이용해서 구현한다.
참조 카운팅 기능을 갖는 객체는 내부적으로 스마트 포인터를 이용해서 참조 카운팅되는 객체를 가리키고 있는다.
참조 카운팅 되는 객체는 참조 카운팅에 관련된 기능을 구현한 기본 클래스를 상속 받아서 구현하고, 실제 참조되는 객체를 가리킨다.
여기서 실제 참조되는 객체는 이미 존재하는 클래스일 수도 있고,
이미 존재하지 않는 클래스일 경우에는 참조 카운팅 기본 클래스를 상속받는 클래스가 내부적으로 구현할 수도 있다.
참조 카운팅은 위와 같이 복잡한 클래스들의 조합으로 구성되므로 사용하는데 비용이 발생한다.
그러므로 이 비용을 지불하더라도 얻는 이득이 더 클 때 사용해야 하며,
이를 확인하는 것은 프로그래머의 직관이 아니라 프로파일러의 결과가 되어야 한다.

More Related Content

What's hot

M5 1 1
M5 1 1M5 1 1
M5 1 1nexthw
 
Effective c++ Chapter1,2
Effective c++ Chapter1,2Effective c++ Chapter1,2
Effective c++ Chapter1,2문익 장
 
effective c++ chapter 3~4 정리
effective c++ chapter 3~4 정리effective c++ chapter 3~4 정리
effective c++ chapter 3~4 정리
Injae Lee
 
게임 개발에 자주 사용되는 디자인 패턴
게임 개발에 자주 사용되는 디자인 패턴게임 개발에 자주 사용되는 디자인 패턴
게임 개발에 자주 사용되는 디자인 패턴
예림 임
 
Effective c++ 정리 chapter 4
Effective c++ 정리 chapter 4Effective c++ 정리 chapter 4
Effective c++ 정리 chapter 4연우 김
 
이펙티브 C++ 5,6 장 스터디
이펙티브 C++ 5,6 장 스터디이펙티브 C++ 5,6 장 스터디
이펙티브 C++ 5,6 장 스터디
quxn6
 
이펙티브 C++ 공부
이펙티브 C++ 공부이펙티브 C++ 공부
이펙티브 C++ 공부quxn6
 
Effective c++ 정리 chapter 8
Effective c++ 정리 chapter 8Effective c++ 정리 chapter 8
Effective c++ 정리 chapter 8
연우 김
 
Effective c++ chapter 1,2 요약
Effective c++ chapter 1,2 요약Effective c++ chapter 1,2 요약
Effective c++ chapter 1,2 요약
Nam Hyeonuk
 
More effective c++ chapter1 2_dcshin
More effective c++ chapter1 2_dcshinMore effective c++ chapter1 2_dcshin
More effective c++ chapter1 2_dcshin
Dong Chan Shin
 
Effective C++ Chaper 1
Effective C++ Chaper 1Effective C++ Chaper 1
Effective C++ Chaper 1
연우 김
 
React 애플리케이션 아키텍처 - 아무도 알려주지 않아서 혼자서 삽질했다.
React 애플리케이션 아키텍처 - 아무도 알려주지 않아서 혼자서 삽질했다.React 애플리케이션 아키텍처 - 아무도 알려주지 않아서 혼자서 삽질했다.
React 애플리케이션 아키텍처 - 아무도 알려주지 않아서 혼자서 삽질했다.
병대 손
 
Effective c++ 정리 chapter 6
Effective c++ 정리 chapter 6Effective c++ 정리 chapter 6
Effective c++ 정리 chapter 6
연우 김
 
More effective c++ 2
More effective c++ 2More effective c++ 2
More effective c++ 2현찬 양
 
More effective c++ 3
More effective c++ 3More effective c++ 3
More effective c++ 3현찬 양
 
8.hooks
8.hooks8.hooks
8.hooks
Daniel Lim
 
Effective c++ 챕터 2 정리
Effective c++ 챕터 2 정리Effective c++ 챕터 2 정리
Effective c++ 챕터 2 정리
연우 김
 
Effective C++ Chapter 1 Summary
Effective C++ Chapter 1 SummaryEffective C++ Chapter 1 Summary
Effective C++ Chapter 1 Summary
SeungYeonChoi10
 
Effective C++ 정리 chapter 3
Effective C++ 정리 chapter 3Effective C++ 정리 chapter 3
Effective C++ 정리 chapter 3
연우 김
 
Effective c++ chapter3, 4 요약본
Effective c++ chapter3, 4 요약본Effective c++ chapter3, 4 요약본
Effective c++ chapter3, 4 요약본
Dong Chan Shin
 

What's hot (20)

M5 1 1
M5 1 1M5 1 1
M5 1 1
 
Effective c++ Chapter1,2
Effective c++ Chapter1,2Effective c++ Chapter1,2
Effective c++ Chapter1,2
 
effective c++ chapter 3~4 정리
effective c++ chapter 3~4 정리effective c++ chapter 3~4 정리
effective c++ chapter 3~4 정리
 
게임 개발에 자주 사용되는 디자인 패턴
게임 개발에 자주 사용되는 디자인 패턴게임 개발에 자주 사용되는 디자인 패턴
게임 개발에 자주 사용되는 디자인 패턴
 
Effective c++ 정리 chapter 4
Effective c++ 정리 chapter 4Effective c++ 정리 chapter 4
Effective c++ 정리 chapter 4
 
이펙티브 C++ 5,6 장 스터디
이펙티브 C++ 5,6 장 스터디이펙티브 C++ 5,6 장 스터디
이펙티브 C++ 5,6 장 스터디
 
이펙티브 C++ 공부
이펙티브 C++ 공부이펙티브 C++ 공부
이펙티브 C++ 공부
 
Effective c++ 정리 chapter 8
Effective c++ 정리 chapter 8Effective c++ 정리 chapter 8
Effective c++ 정리 chapter 8
 
Effective c++ chapter 1,2 요약
Effective c++ chapter 1,2 요약Effective c++ chapter 1,2 요약
Effective c++ chapter 1,2 요약
 
More effective c++ chapter1 2_dcshin
More effective c++ chapter1 2_dcshinMore effective c++ chapter1 2_dcshin
More effective c++ chapter1 2_dcshin
 
Effective C++ Chaper 1
Effective C++ Chaper 1Effective C++ Chaper 1
Effective C++ Chaper 1
 
React 애플리케이션 아키텍처 - 아무도 알려주지 않아서 혼자서 삽질했다.
React 애플리케이션 아키텍처 - 아무도 알려주지 않아서 혼자서 삽질했다.React 애플리케이션 아키텍처 - 아무도 알려주지 않아서 혼자서 삽질했다.
React 애플리케이션 아키텍처 - 아무도 알려주지 않아서 혼자서 삽질했다.
 
Effective c++ 정리 chapter 6
Effective c++ 정리 chapter 6Effective c++ 정리 chapter 6
Effective c++ 정리 chapter 6
 
More effective c++ 2
More effective c++ 2More effective c++ 2
More effective c++ 2
 
More effective c++ 3
More effective c++ 3More effective c++ 3
More effective c++ 3
 
8.hooks
8.hooks8.hooks
8.hooks
 
Effective c++ 챕터 2 정리
Effective c++ 챕터 2 정리Effective c++ 챕터 2 정리
Effective c++ 챕터 2 정리
 
Effective C++ Chapter 1 Summary
Effective C++ Chapter 1 SummaryEffective C++ Chapter 1 Summary
Effective C++ Chapter 1 Summary
 
Effective C++ 정리 chapter 3
Effective C++ 정리 chapter 3Effective C++ 정리 chapter 3
Effective C++ 정리 chapter 3
 
Effective c++ chapter3, 4 요약본
Effective c++ chapter3, 4 요약본Effective c++ chapter3, 4 요약본
Effective c++ chapter3, 4 요약본
 

Viewers also liked

introduction to dynamic programming and linear programming
introduction to dynamic programming and linear programmingintroduction to dynamic programming and linear programming
introduction to dynamic programming and linear programming
Gyeongwook Choi
 
approximation algorithm
approximation algorithmapproximation algorithm
approximation algorithm
Gyeongwook Choi
 
강화 학습 기초 Reinforcement Learning an introduction
강화 학습 기초 Reinforcement Learning an introduction강화 학습 기초 Reinforcement Learning an introduction
강화 학습 기초 Reinforcement Learning an introduction
Taehoon Kim
 

Viewers also liked (7)

Mec 56
Mec 56Mec 56
Mec 56
 
introduction to dynamic programming and linear programming
introduction to dynamic programming and linear programmingintroduction to dynamic programming and linear programming
introduction to dynamic programming and linear programming
 
MEC++ 1, 2
MEC++ 1, 2MEC++ 1, 2
MEC++ 1, 2
 
EC 789
EC 789EC 789
EC 789
 
MEC++ 3,4
MEC++ 3,4MEC++ 3,4
MEC++ 3,4
 
approximation algorithm
approximation algorithmapproximation algorithm
approximation algorithm
 
강화 학습 기초 Reinforcement Learning an introduction
강화 학습 기초 Reinforcement Learning an introduction강화 학습 기초 Reinforcement Learning an introduction
강화 학습 기초 Reinforcement Learning an introduction
 

Similar to MEC++ 5

Effective c++ 1~8장
Effective c++ 1~8장 Effective c++ 1~8장
Effective c++ 1~8장
Shin heemin
 
모어 이펙티브 c++ 5장 스터디
모어 이펙티브 c++ 5장 스터디모어 이펙티브 c++ 5장 스터디
모어 이펙티브 c++ 5장 스터디
quxn6
 
More effective c++ chapter4 이후 항목 29까지
More effective c++ chapter4 이후 항목 29까지More effective c++ chapter4 이후 항목 29까지
More effective c++ chapter4 이후 항목 29까지
Dong Chan Shin
 
Mec chapter 5,6
Mec chapter 5,6Mec chapter 5,6
Mec chapter 5,6문익 장
 
이펙티브 C++ 스터디
이펙티브 C++ 스터디이펙티브 C++ 스터디
이펙티브 C++ 스터디
quxn6
 
Api design for c++ pattern
Api design for c++ patternApi design for c++ pattern
Api design for c++ pattern
jinho park
 
Api design for c++ ch3 pattern
Api design for c++ ch3 patternApi design for c++ ch3 pattern
Api design for c++ ch3 patternjinho park
 
Effective java
Effective javaEffective java
Effective java
Haeil Yi
 
More effective c++ chapter1,2
More effective c++ chapter1,2More effective c++ chapter1,2
More effective c++ chapter1,2문익 장
 
디자인패턴 1~13
디자인패턴 1~13디자인패턴 1~13
디자인패턴 1~13
Shin heemin
 
Head first디자인패턴 1~13_희민_호준
Head first디자인패턴 1~13_희민_호준Head first디자인패턴 1~13_희민_호준
Head first디자인패턴 1~13_희민_호준
HoJun Sung
 
2014-15 Intermediate C++ Study #6
2014-15 Intermediate C++ Study #62014-15 Intermediate C++ Study #6
2014-15 Intermediate C++ Study #6
Chris Ohk
 
More effective c++ 3주차
More effective c++ 3주차More effective c++ 3주차
More effective c++ 3주차Injae Lee
 
Mec++ chapter3,4
Mec++ chapter3,4Mec++ chapter3,4
Mec++ chapter3,4문익 장
 
Effective c++(chapter3,4)
Effective c++(chapter3,4)Effective c++(chapter3,4)
Effective c++(chapter3,4)문익 장
 
Design patterns
Design patternsDesign patterns
Design patterns
Joshua Yoon
 
Chapter5 ~ 6
Chapter5 ~ 6Chapter5 ~ 6
Chapter5 ~ 6Injae Lee
 
Windows via c++ part 1
Windows via c++ part 1Windows via c++ part 1
Windows via c++ part 1
Shin heemin
 
Effective cpp
Effective cppEffective cpp
Effective cpp
TonyCms
 
게임프로그래밍입문 7
게임프로그래밍입문 7게임프로그래밍입문 7
게임프로그래밍입문 7
Yeonah Ki
 

Similar to MEC++ 5 (20)

Effective c++ 1~8장
Effective c++ 1~8장 Effective c++ 1~8장
Effective c++ 1~8장
 
모어 이펙티브 c++ 5장 스터디
모어 이펙티브 c++ 5장 스터디모어 이펙티브 c++ 5장 스터디
모어 이펙티브 c++ 5장 스터디
 
More effective c++ chapter4 이후 항목 29까지
More effective c++ chapter4 이후 항목 29까지More effective c++ chapter4 이후 항목 29까지
More effective c++ chapter4 이후 항목 29까지
 
Mec chapter 5,6
Mec chapter 5,6Mec chapter 5,6
Mec chapter 5,6
 
이펙티브 C++ 스터디
이펙티브 C++ 스터디이펙티브 C++ 스터디
이펙티브 C++ 스터디
 
Api design for c++ pattern
Api design for c++ patternApi design for c++ pattern
Api design for c++ pattern
 
Api design for c++ ch3 pattern
Api design for c++ ch3 patternApi design for c++ ch3 pattern
Api design for c++ ch3 pattern
 
Effective java
Effective javaEffective java
Effective java
 
More effective c++ chapter1,2
More effective c++ chapter1,2More effective c++ chapter1,2
More effective c++ chapter1,2
 
디자인패턴 1~13
디자인패턴 1~13디자인패턴 1~13
디자인패턴 1~13
 
Head first디자인패턴 1~13_희민_호준
Head first디자인패턴 1~13_희민_호준Head first디자인패턴 1~13_희민_호준
Head first디자인패턴 1~13_희민_호준
 
2014-15 Intermediate C++ Study #6
2014-15 Intermediate C++ Study #62014-15 Intermediate C++ Study #6
2014-15 Intermediate C++ Study #6
 
More effective c++ 3주차
More effective c++ 3주차More effective c++ 3주차
More effective c++ 3주차
 
Mec++ chapter3,4
Mec++ chapter3,4Mec++ chapter3,4
Mec++ chapter3,4
 
Effective c++(chapter3,4)
Effective c++(chapter3,4)Effective c++(chapter3,4)
Effective c++(chapter3,4)
 
Design patterns
Design patternsDesign patterns
Design patterns
 
Chapter5 ~ 6
Chapter5 ~ 6Chapter5 ~ 6
Chapter5 ~ 6
 
Windows via c++ part 1
Windows via c++ part 1Windows via c++ part 1
Windows via c++ part 1
 
Effective cpp
Effective cppEffective cpp
Effective cpp
 
게임프로그래밍입문 7
게임프로그래밍입문 7게임프로그래밍입문 7
게임프로그래밍입문 7
 

MEC++ 5

  • 1. 항목 25 : 생성자 함수와 비멤버 함수를 가상함수처럼 만드는 방법
  • 2. 상속 관계에 있는 객체의 생성 타입을 런타임에 결정해서 작동하게 하고 싶을 때 사용한다. 흔히 사용하는 것은 가상 복사 생성자라는 경우이다. 기본 클래스에 복사 생성을 하는 함수를 순수 가상 함수로 만들고, 파생 클래스에서 이 함수를 구현할 때 파생 클래스 본인을 복사 생성해서 반환하는 방식으로 구현한다. 비멤버 함수를 가상함수처럼 동작하게 할 때는 기본 클래스는 원하는 함수를 순수 가상함수로 만들고, 파생 클래스들은 이 함수를 자신의 클래스 맞게 구현한다. 그리고 클래스 외부에 기본 클래스를 인자로 받는 함수를 하나 만들고 내부에서는 그 클래스의 순수 가상 함수를 호출하도록 한다. 그러면 비멤버 함수에 파생 클래스를 인자로 넣어서 호출하면, 파생 클래스가 구현한 멤버 함수가 호출되어서 비멤버 함수를 가상함수처럼 사용할 수 있게 된다.
  • 3. 항목 26 : 클래스 인스턴스의 개수를 의도대로 제한하는 방법
  • 4. 객체를 전혀 생성하지 못하게 하려면 생성자를 private에 둔다. 객체를 하나만 생성하게 하려면 생성자를 private에 두고 전역에서 이 함수를 호출하는 함수를 프렌드로 등록한다. 그리고 이 전역함수는 해당 객체를 static으로 만들어서 반환한다. 결국 이 객체의 생성자를 호출할 수 있는 것은 전역 함수 하나 뿐이고, 이 전역함수는 해당 객체를 static으로 선언해서 사용하므로 딱 하나만 만들어지게 된다. 참고로 이 static 객체가 생성되는 것은 최초로 이 함수가 불릴 때이다. 만약 static 객체를 해당 객체 안에 담아두고 사용할 경우 이 static 객체는 사용여부와 상관없이 항상 메모리에 생성되고, 다른 static 객체들 사이에 생성되는 순서가 명확히 보장되지 않는다는 단점을 가지게 된다.
  • 5. 객체가 생성되는 수를 제한하고 싶을 때 고려해야 할 상황은 객체 생성이 일반적으로 프로그래머가 명시적으로 생성하는 것이 아니라 파생된 객체의 기본 클래스 부분으로 생성될 때와 다른 객체의 클래스 멤버로 생성될 때이다. 이 경우에도 생성자를 private로 둠으로써 문제를 해결할 수 있다. 즉 상속되거나 클래스 멤버가 될 수 없도록 하는 것이다. 대신 이 경우에는 항상 생성 결과가 포인터로 반환되므로 객체를 생성한 쪽에서 해제를 해주어야 한다. 스마트 포인터를 이용해서 이 부분을 쉽게 관리할 수도 있다. 객체의 수를 관리하는 것은 멤버로 객체의 수를 기록하는 static 변수를 둠으로써 가능하다. 객체가 생성되는 경우가 명시적으로 생성하는 것으로 제한하기 위해서 복사 생성등도 private로 두고, 생성자를 호출할 때 이 static 변수의 수를 확인해서 생성을 결정하도록 하는 것이다.
  • 6. 객체 수를 제한하는 기능이 필요한 클래스가 많을 때는 이 기능을 기본 클래스로 만들고, 이를 상속하게 함으로써 사용할 수 있다. 구현 방법은 생성 및 소멸자를 protected로 두어서 상속 받은 클래스들만 접근 할 수 있게 하고, 이 생성자에서 앞에서 언급한 객체의 수를 확인하는 로직을 둔다. 파생 클래스를 이 기본 클래스를 private 상속하고, 기본 클래스의 요소들 중 필요한 것들은 using 선언을 통해서 사용할 수 있게 등록한다. 파생 클래스가 생성되면 기본 클래스의 생성자가 먼저 호출되므로 파생 클래스에서는 개수를 확인하는 로직을 둘 필요없이 기본 클래스 생성 단계에서 객체 수를 제한하는 로직이 적용되어 작업이 진행된다.
  • 7. 항목 27 : 힙에만 생성되거나 힙에는 만들어지지 않는 특수한 클래스를 만드는 방법
  • 8. 객체가 힙에만 생성되게 하기 소멸자만 private로 둔다. 핵심은 new로만 생성하게 하고 암시적으로 객체를 생성 소멸을 하지 못하게 하는 것이다. 생성자를 private로 두지 않는 것은 그 경우에는 복사 생성자 및 기본 생성자를 고려해야 하므로 귀찮다. 어떤 객체가 힙에 생성되었는지, 그렇지 않은지를 알아내는 방법 한 가지 방법은 new 호출을 통해 생성되는 메모리 주소를 기록하고, 이와 대조를 통해 알아내는 것이다. 하지만 전역 new를 오버라이딩 한다는 부담과 메모리 주소를 하나하나 대조를 하는 비용이 크다는 단점과 다중 상속 및 가상 상속을 통해 생성된 객체에서는 제대로 작동하지 않는다는 문제를 가지고 있다. 그래서 추상 믹스인 기본 클래스라는 것을 만들어서 이를 상속해서 사용함으로써 문제를 해결한다. 다중 상속과 가상 상속의 문제는 객체의 주소가 여러 개라는 점이다. 이때 dynamic_cast를 사용하면 추상 믹스인 기본 클래스를 상속 받은 파생 클래스의 주소로 변환할 수 있게 되고, 이는 new 호출을 통해 생성할 때 사용한 주소와 같으므로 앞에서 발생한 문제를 해결할 수 있다. 객체가 힙에만 생성되지 않게 하기 객체가 힙에 생성되는 것은 operator new를 통해서만 가능하므로 이를 private로 두는 것으로 해결 가능하다.
  • 9. 항목 28 : 스마트 포인터
  • 10. 스마트 포인터의 생성, 대입, 소멸 스마트 포인터는 포인터 객체가 소멸되면 실제 내부에서 가리키고 있던 객체를 삭제한다. 문제는 스마트 포인터를 복사하면 해당 객체를 두 번 삭제할 수 있다. 이 문제를 막기 위해서 실재 객체를 생성 복사하거나 복사 대입을 막을 수도 있지만 소유권을 이전하는 방법도 가능하다. 이 방식은 복사 대입이 일어날 때 원래 있던 스마트 포인터를 삭제한다. 결국 실제 객체를 가리키는 스마트 포인터는 복사 대입된 것 하나만 유지된다. 하지만 원래 있던 스마트 포인터는 nullptr를 가리키고 있으므로 사용상 주의가 필요하다. 역참조 연산자 구현하기 스마트 포인터 내부에서 가리키는 실제 대상 객체가 nullptr인지 아닌지 확인해서 대상 객체의 참조자를 반환하면 된다. 스마트 포인터가 nullptr인지 점검 이를 확인하는 함수가 있어도 되지만 스마트 포인터를 일반 포인터처럼 사용할 수 없게 된다. operator!를 오버로딩해서 스마트 포인터가 nullptr인 경우에만 true를 반환하게 함으로써 이 부분을 해결할 수 있다.
  • 11. 스마트 포인터를 벙어리 포인터로 변환하기 스마트 포인터를 일반 포인터로 변환하기 위해 암시적 변환을 사용하면 발생하는 문제가 많으므로 변환하지 말자 스마트 포인터와 상속 기반의 타입변환 멤버 함수 템플릿을 만들어 두는 것으로 가능하다. 하지만 이 변환은 스마트 포인터가 가리키는 객체의 상속 구조와는 상관없이 작동하므로 실제 포인터를 캐스팅하는 것과 같을 수는 없다. 스마트 포인터와 const 상수 객체와 비상수 객체의 관계를 보면 상수 객체가 할 수 있는 비상수 객체가 모두 다 할 수 있고, 상수 객체가 못하는 일도 비상수 객체는 할 수 있다는 특징을 이용해서 상속관계를 이용해서 만든다. 상속 스마트 포인터를 만들고 멤버에 union을 이용해서 가리키고자 하는 대상 객체를 가리키는 포인터를 상수 버전과 비상수 버전 모두 넣어둔다. 그리고 비상수 스마트 포인터를 이 상수 스마트 포인터를 상속받아서 구현한다.
  • 12. 항목 29 : 참조 카운팅
  • 13. 참조 카운팅은 기본적으로 같은 값을 가지는 객체를 가리킬 때 각각 생성하지 말고 하나를 만들어서 공유하는 것이다. 그리고 공유 참조 수를 체크해서 참조 수가 0이 되면 해당 객체를 삭제한다. 주의할 점은 대상을 수정하면 참조하는 모든 객체들이 변경되므로 수정할 때는 복사해서 새로운 객체를 만들어서 참조하게 한다. 이런 조건들을 만족하게 하려면 복잡한 코드들이 필요해진다. 그래서 이를 쉽게 구현하기 위해서는 참조 기능을 갖는 기본 클래스의 상속과 스마트 포인터를 이용해서 구현한다. 참조 카운팅 기능을 갖는 객체는 내부적으로 스마트 포인터를 이용해서 참조 카운팅되는 객체를 가리키고 있는다. 참조 카운팅 되는 객체는 참조 카운팅에 관련된 기능을 구현한 기본 클래스를 상속 받아서 구현하고, 실제 참조되는 객체를 가리킨다. 여기서 실제 참조되는 객체는 이미 존재하는 클래스일 수도 있고, 이미 존재하지 않는 클래스일 경우에는 참조 카운팅 기본 클래스를 상속받는 클래스가 내부적으로 구현할 수도 있다. 참조 카운팅은 위와 같이 복잡한 클래스들의 조합으로 구성되므로 사용하는데 비용이 발생한다. 그러므로 이 비용을 지불하더라도 얻는 이득이 더 클 때 사용해야 하며, 이를 확인하는 것은 프로그래머의 직관이 아니라 프로파일러의 결과가 되어야 한다.