2. 1.스마트 포인터 정의 및 역활 c++정리-스마트포인터
1. 정의:임의의 객체가 다른 타입의 포인터 역할을 하는것.
2. 장점:
멤버 객체를 둘러싸고 있는 객체 이다.
즉, 생성/복사/대입/소멸의 모든 과정을 사용자가 제어 할 수 있다.
대표적 활용이 소멸자에서의 멤버 객체 자동 삭제 이다.
3. 역할
a. 멤버 객체를 소멸자에서 자동으로 delete한다.
b. 스마트 포인터 객체로 멤버 객체에 접근 할 수 있다.
c. 모든 type에 대해서 스마트 포인터를 사용 할 수 있다.
d. 얕은 복사 문제를 해결할 수 있다.
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. 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. 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. 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. 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. 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. 안드로이드에서의 스마트 포인터 사용 예 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.cpp
sp<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) const
sp<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); }
}