C++정리 스마트포인터

6,682 views
6,190 views

Published on

Published in: Technology

C++정리 스마트포인터

  1. 1. c++정리-스마트포인터c++정리-스마트포인터 박철희
  2. 2. 1.스마트 포인터 정의 및 역활 c++정리-스마트포인터1. 정의:임의의 객체가 다른 타입의 포인터 역할을 하는것.2. 장점: 멤버 객체를 둘러싸고 있는 객체 이다. 즉, 생성/복사/대입/소멸의 모든 과정을 사용자가 제어 할 수 있다. 대표적 활용이 소멸자에서의 멤버 객체 자동 삭제 이다.3. 역할 a. 멤버 객체를 소멸자에서 자동으로 delete한다. b. 스마트 포인터 객체로 멤버 객체에 접근 할 수 있다. c. 모든 type에 대해서 스마트 포인터를 사용 할 수 있다. d. 얕은 복사 문제를 해결할 수 있다.
  3. 3. a. 멤버 객체를 소멸자에서 자동으로 delete한다. c++정리-스마트포인터 class Car { public: void Go() { cout << "Car Go" << endl; } }; class ptr { Car* obj; public: ptr( Car* p = 0 ) : obj(p) {} //생성자에서 p를 obj로 넣어준다. //ptr이 객체이기 때문에 함수를 벗어날때 소멸자를 불러준다. //그래서 생성한 obj를 delete하는 code를 넣어주면 사용자가 따로 obj를 delete하는 // code를 넣을 필요가 없다. ~ptr() { delete obj; } } int main() { ptr p = new Car; // ptr p( new Car ) 와 같다. }
  4. 4. b. 스마트 포인터 객체로 멤버 객체에 접근 할 수 있다. c++정리-스마트포인터 class Car { public: void Go() { cout << "Car Go" << endl; } }; class ptr { Car* obj; public: ptr( Car* p = 0 ) : obj(p) {} //생성자에서 p를 obj로 copy한다. ~ptr() { delete obj; } Car* operator->() { return obj; }  객체 멤버에 접근하기 위한 ‘->’ 재정의 Car& operator*() { return *obj; }  객체 멤버에 접근하기 위한 ‘*’ 재정의 } int main() { ptr p = new Car; // ptr p( new Car ) p->Go();//OK Car의 go 호출 p->  p.operator->() 호출. (*p).GO(); //OK Car의 go 호출 *p  p.operator*() 호출. }
  5. 5. c. 모든 type에 대해서 스마트 포인터를 사용 할 수 있다. c++정리-스마트포인터 template으로 만들어야 한다. template<typename T> class ptr  typename T에 대한 스마트 포인터를 사용할 수 있다. { T* obj; public: ptr( T* p = 0 ) : obj(p) {}  생성자에서 type T의 객체를 obj로 복사 ~ptr() { delete obj; }  소멸자에서 자동으로 obj 삭제 T* operator->() { return obj; } T& operator*() { return *obj; } type T의 객체에 접근 하기 위한 연산자 재정의 };
  6. 6. d. 얕은 복사 문제를 해결할 수 있다. c++정리-스마트포인터1)소유권 이전 방법 사용template<typename T> class ptr{ T* obj;public: ptr( ptr& p ) : obj(p.obj) //먼저 얕은 복사를 하고. { p.obj = 0; // 기존 포인터는 reset 한다.(이전 스마트 포인터의 소유권을 포기한다.) } ptr( T* p = 0 ) : obj(p) {} //생성자 ~ptr() { delete obj; } //소멸자 T* operator->() { return obj; } //연산자 재정의 T& operator*() { return *obj; }};int main(){ ptr<int> p1 = new int; *p1 = 10; ptr<int> p2 = p1; // 이 순간 공유가 아니라 p2로 자원이 전달됩니다. cout << *p1 << endl; // 1.. runtime error.. cout << *p2 << endl; // 2. ok..} Cf. c++ 표준 library(STL)에는 소유권 이전 스마트 포인터인 auto_prt<> 이 있다. int main() { auto_ptr<int> p1( new int ); *p1 = 10; auto_ptr<int> p2(p1); // 소유권 이전 cout << *p1 << endl; // runtime error cout << *p2 << endl; // 10 }
  7. 7. d. 얕은 복사 문제를 해결할 수 있다. c++정리-스마트포인터2)참조 계수 기반의 스마트 포인터template<typename T> class ptr int main(){ { T* obj; ptr<int> p1 = new int; int* ref; // 참조계수를 위한 변수public: *p1 = 10; ptr( T* p = 0 ) : obj(p) { ptr<int> p2 = p1; ref = new int(1); //생성자에서 참조 계수 생성. } cout << *p1 << endl; //ok 10 cout << *p2 << endl; //ok 10 //참조계수로 구현한 복사 생성자 } ptr( const ptr& p ) : obj(p.obj), ref(p.ref) { ++(*ref); } //소멸자 ~ptr() { Cf. c++ 표준 library(STL)에는 참조 계수 기반의 스마트 포인터인 if ( --(*ref) == 0 ) //ref가 0일 경우만 객체 delete shared_ptr<> 가 있다. { int main() delete obj; { delete ref; shared_ptr<int> p1( new int); } *p1 = 10; } shared_ptr<int> p2(p1);//p1의 멤버가 p2로 copy되면서 참조계수 1증가. cout << *p1 << endl; //ok 10 cout << *p2 << endl; //ok 10 T* operator->() { return obj; } } T& operator*() { return *obj; }};
  8. 8. d. 얕은 복사 문제를 해결할 수 있다. c++정리-스마트포인터3) 객체 내부에 참조계수를 관리하자. 스마트 포인터의 생성자,소멸자에서 객체 내부의 incstrong,decstrong을 호출하게 하자.객체 내부에 mCount 참조계수 관리 스마트 포인터의 생성자,소멸자에서 객체 내부의 incstrong,decstrong을 호출 함class Car{ template<typename T> class sp int mCount; //참조 계수 {public: T* m_ptr; public: Car() : mCount(0) {}//생성자 void incStrong() { ++mCount; } //생성자 void decStrong() sp( T* other = 0 ) : m_ptr(other) { { if ( --mCount == 0 ) delete this; // 자신을 스스로 파괴 함. if ( m_ptr ) m_ptr->incStrong(); //객체의 incStrong 호출 } }}; //복사생성자 sp( const sp& p ) : m_ptr( p.m_ptr ) { if ( m_ptr ) m_ptr->incStrong(); //객체의 incStrong 호출 } int main() { //소멸자 ~sp() sp<Car> p1 = new Car;// 생성자에서 incStrong 부름. { if ( m_ptr ) m_ptr->decStrong(); //객체의 decStrong 호출 sp<Car> p2 = p1; } //복사생성자에서 incStrong 부름. p2=new Car(p1); 와 같음. }; sp<int> p3 = new int; //error int class에서 incStrong , decStrong 이 없다. 그래서, 안드로이드에서는 최상위 부모 class인 Refbase에 incStrong, decStrong 을 정의해 놓고 상속받아서 사용하게 되어있다. }
  9. 9. 안드로이드에서의 스마트 포인터 사용 예 c++정리-스마트포인터-안드로이드에서는 Strongpointer 객체로 스마트 포인터 기능을 구현한다. 또한, 최상위 class인 Refbase에 참조계수가 정의 되어 있다.(incStrong, decStrong )StrongPointer.h //소멸자 정의template <typename T> sp<T>::~sp()class sp {{ if (m_ptr) m_ptr->decStrong(this);public: } sp(T* other); //생성자 선언 결론적으로 안드로이드에서는 최상위 class인 Refbas의 sp(const sp<T>& other); //복사 생성자 선언 incStrong,decStrong이 불리게 된다. ~sp(); //소멸자 선언 //연산자 재정의 Refbase.h inline T& operator* () const { return *m_ptr; } class RefBase inline T* operator-> () const { return m_ptr; } { inline T* get() const { return m_ptr; } public: void incStrong(const void* id) const;private: void decStrong(const void* id) const; T* m_ptr; … }}//생성자 정의template<typename T> Refbase.cppsp<T>::sp(T* other) void RefBase::incStrong(const void* id) const: m_ptr(other) { { //참조 계수 값 증가 if (other) other->incStrong(this); T의 incStrong 호출 const int32_t c = android_atomic_inc(&refs->mStrong); } }//복사생성자 정의template<typename T> void RefBase::decStrong(const void* id) constsp<T>::sp(const sp<T>& other) {: m_ptr(other.m_ptr) //참조 계수 값 감소 { const int32_t c = android_atomic_dec(&refs->mStrong); if (m_ptr) m_ptr->incStrong(this); } }

×