[c++ korea] effective modern c++ study item 19 use shared ptr for shared ownership resource...
TRANSCRIPT
Effective Modern C++ Study C++ Korea
발표자 : 윤석준
Effective Modern C++ Study C++ Korea 5
1959년 LISP의 문제를 해결하기 위해 John McCarthy가 개발
Java, C#, 대부분의 Script 언어에서 쓰이고 있음
장점 (버그를 줄이거나 완전히 막아줌)
- 유효하지 않은 포인터에 접근
- 이중 해제
- Memory Leak
단점 (주로 성능적 이슈)
- GC 알고리즘의 오버헤드
(프로그래머는 빤히 아는데… 왜 그걸 굳이 또 계산해가면서…)
- Timing 예측 불가 (중요한 타이밍에 버벅)
- 자원해제 시점을 모른다.
http://ko.wikipedia.org/wiki/쓰레기_수집_(컴퓨터_과학)
GC의 장점 + !단점이 가능할까 ?
Effective Modern C++ Study C++ Korea 7
• 직접적으로 Object를 소유하지 않음
• 여러 개의 std::shared_ptr이 하나의 Object를 공유
• Object는 마지막 std::shared_ptr이 사라지면 해제
#include <memory>
GC의 장점 : Object의 수명에 대해 신경 쓸 필요가 없다.
!단점 : 원하는 시점에 해제가 가능하다.
• 사용법은 생략
• 참조 사이트 : http://devluna.blogspot.kr/2014/12/stl-sharedptr-weakptr.html
Effective Modern C++ Study C++ Korea 9
해당 Object를 참조하고 있는 std::shared_ptr 의 개수
std::shared_ptr Constructor : Ref. Count ++
std::shared_ptr Destructor : Ref. Count - -
std::shared_ptr ::operator = : Left-hand Ref. Count ++, Right-hand Ref. Count - -
Atfer Ref. Count - - , if Ref. Count == 0 then delete object
Effective Modern C++ Study C++ Korea 10
1. Memory Issue
• Raw Pointer 크기의 2배 : Object Pointer + Control Block Pointer (include Ref. Count)
• Heap Memory (Dynamic Allocation) : Object 자체는 Ref. Count가 필요가 없다.
2. Performance Issue
• Atomic 연산 (sizse는 word)
• 대부분의 std::shared_ptr 은 Ref. Count ++
(Move 생성자, Move 연산자는 Ref. Count 변화 없음)
Effective Modern C++ Study C++ Korea 12
auto LogDel = [](T *pw)
{
makeLog(pw);
delete pw;
};
std::unique_ptr<T, decltype(LogDel)> UPW(new T, LogDel); // deleter type is part of ptr type
std::shared_ptr<T> SPW(new T, LogDel); // deleter type is not part of ptr type
- std::unique_ptr : template type의 부분
- std::shared_ptr : type의 일부가 아님
서로 다른 deleter를 가진 std::shared_ptr을 하나의 Container에 담을 수 있다.
Effective Modern C++ Study C++ Korea 13
- std::unique_ptr 은 custom deleter 크기를 포함
- std::shared_ptr 은 custom deleter 여부와 상관없이 무조건 Pointer 2개의 크기
• custom deleter는 function object 이다.
• 그럼 어디 저장 될까 ?
Control Block에 저장된다.
Effective Modern C++ Study C++ Korea 15
- Reference Count
- Weak Count
- Custom Deleter (if exists)
- Allocator (if exists)
Effective Modern C++ Study C++ Korea 16
- std::make_shared
- Unique-ownership Pointer (std::unique_ptr, std::auto_ptr)로 부터
std::shared_ptr 을 만들 때
- Raw Pointer로부터 std::shared_ptr 을 만들 때
OK
OK (std::shared_ptr 로 부터 std::unique_ptr 는 불가능 하니깐)
가만 ! 딱 봐도 먼가 이상한 Smell 이…. 스멜스멜….
Effective Modern C++ Study C++ Korea 17
auto P = new T;
{
std::shared_ptr<T> SP1(P, makeLog); // create control block for *p
{
std::shared_ptr<T> SP2(P, makeLog);// create 2nd control block for *p
}
} 여기서 SP2의 Ref. Count == 0 이 되니, P의 dtor가 호출.
여기서 SP1의 Ref. Count == 0 이 되니, P의 dtor가 호출.
가만…. 이미 P는 해제됬는데… 아놔 어떡하지 ???
1. Raw Pointer로 부터 std::shared_ptr을 생성하지 말자.
(하지만, custom deleter를 사용할려면 std::make_shared를 사용 못하는데 ???)
2. 어쩔수 없다면 Raw Pointer를 변수에 담지말고 new로 생성한 R-Value를 사용
std::shared_ptr<T> SP(new T, LogDel); // direct use of new
Effective Modern C++ Study C++ Korea 19
std::vector<std::shared_ptr<T>> T_History;
class T { public: void process(); };
void T::process() { T_History.emplace_back(this); // this is wrong
} this는 Raw Pointer
*this의 Control Block는 계속해서 만들어 질 것이다.
Effective Modern C++ Study C++ Korea 20
class T : public std::enable_shared_from_this<T>
{
public:
void process();
};
void T::process()
{
T_History.emplace_back( shared_from_this() );
}
근데… 너 좀 낮설다.
파생 클래스에서 파생 클래스의 템플릿 클래스를 상속받는다 ?
The Curiously Recurring Template Pattern (CRTP)
this로부터 std::shared_ptr은 만들지만 Control Block은 안만든다.
그런데…. 만약 그전에 만들어진 Control Block이 없다면 ?
아놔~ 예외를 발생시킨다.
어떻하지 ????
Factory Method Pattern
http://devluna.blogspot.kr/2015/01/factory-method-pattern.html
Effective Modern C++ Study C++ Korea 21
class T : public std::enable_shared_from_this<T>
{
public:
template<typename... Ts>
static std::shared_ptr<T> create(Ts&&... params);
private:
template<typename... Ts>
T(Ts&&... params);
};
생성자를 private에 선언
Factory method에서 std::shared<T>를 return
Effective Modern C++ Study C++ Korea 23
• Dynamic Allocation
• Size : few Words + custom deleter, allocator
• Virtual Function
• Atomic Calculation
Default는 3 Words
std::make_shared
Object Destructor
1,2 Instruction Cycle
이정도 Cost만 감당한다면, 수명관리를 해준다.
Effective Modern C++ Study C++ Korea 25
• std::shared_ptr는 단일 Pointer에 대해서만 동작
• 그럼 delete[ ] 를 이용해서 custom deleter를 만들면 ?
• std::shared_ptr에는 [ ] 연산자가 없다.
• 결정적으로 단일 개체에 대해서만 derived-to-base 포인트 변환을 지원
Effective Modern C++ Study C++ Korea 27
• std::shared_ptr는 개체에 대한 수명관리를 Garbage Collection 만큼 편리하게 해준다.
• std::unique_ptr에 비해 std::shared_ptr는 개체가 2배 더 크고, Control Block에 대한 오버해
드가 발생하고, Reference Count에 대해서 Atomic 연산을 해야 한다.
• default 자원해제는 delete 지만 custom deleter도 지원한다. deleter의 타입은 std::shared_ptr
의 타입에 영향을 미치지 않는다.
• Raw Pointer를 변수로 만들어서 std::shared_ptr로 만들지 마라.
http://devluna.blogspot.kr/2015/02/item-19-stdsharedptr.html