Android Framework에 있는 C++ 소스를 보다보면 "sp<>" 같은 부분이 나와서 안드로이드 소스 분석을 어렵게 하였다.
C++의 기본 문법에서는 볼 수 없었던 부분이라 많이 헷갈렸는데 구글링을 해보니 Smart Pointer라 불리며, 아래와 같이 잘 정리한 글이 있다.
===========================================================
우리는 자원 관리 클래스(resource management class)와 스마트 포인터(smart pointer)를 직접 작성하고 구현하는 방법을 공부해 보도록 하겠습니다.
자원(resource)이란 사용 후 시스템에 돌려줘야 하는 모든 것을 말합니다.(EC++)
자원은 사용 후 꼭 다시 시스템에 되돌려줘야 하기 때문에 프로그램의 많은 버그가 이 자원 관리 쪽에서 만들어지곤 합니다.
이런 버그를 최소화하기 위해 자원 관리를 자동으로 할 수 있는 자원 관리 클래스를 만들어 사용합니다. 즉 자원 관리를 추상화한 자원 관리 클래스를 만들어 사용하는 것이지요.
프로그램에서 가장 많이 사용하는 대표적인 자원이 heap(동적) 메모리입니다. heap 메모리는 생성 후 꼭 삭제해야 하는 자원입니다.
JAVA나 C#의 장점 중 하나는 객체를 메모리 할당하고 삭제를 신경 쓰지 않아도 된다는 것입니다. 자동으로 객체가 삭제되기 때문입니다.
C++도 객체를 메모리 할당 후 잊어버려도 되는 방법이 있습니다. 바로 스마트 포인터를 사용하는 것입니다.
1, 스마트 포인터의 사용
스마트 포인터를 사용해야 하는 이유를 예제로 설명하겠습니다.
아래는 자원(동적 메모리)이 누출되는 간단한 예입니다.
void DoSomething( )
{
int *pn = new int(10);
//.......
//이곳에서 delete 호출을 하지 않거나
//return, break 예외 등이 발생하면 메모리가 삭제되지 않습니다.
// 두 번 삭제하는 경우에..
delete pn;
}
그래서 자원(메모리)을 자동으로 해제(삭제)할 수 있는 자원 관리 클래스(스마트 포인터 클래스)를 사용하여 동적 객체를 관리합니다.
대표적인 스마트 포인터 클래스가 auto_ptr과 shared_ptr입니다.
auto_ptr은 C++ 표준 라이브러리에 포함되어 있으며 shared_ptr은 std::tr1과 boost 라이브러리에 포함되어 있습니다. vs2008은 vc++ 2008 feature pack을 설치하셔야 합니다.
스마트 포인터는 포인터와 비슷하게 동작하며 포인터 기능에 자동 메모리 삭제 기능이 플러스된 포인터라고 생각하시면 됩니다.
스마트 포인터는 스마트 포인터 클래스의 객체이며 객체가 소멸될 때 소멸자를 이용하여 동적 메모리를 삭제합니다.
(다음에 직접 구현해 보도록 하겠습니다.)
아래는 auto_ptr과 shared_ptr을 사용한 예제입니다.
#include <iostream>
#include <memory>
#include <boost/shared_ptr.hpp>
using namespace std;
using namespace boost;
void DoSomething( )
{
auto_ptr<int> ptr1= auto_ptr<int>( new int(10) );
shared_ptr<int> ptr2= shared_ptr<int>( new int(50) );
int *ptr3 = new int(100);
cout << *ptr1 << endl;
cout << *ptr2 << endl;
cout << *ptr3 << endl;
delete ptr3;
// ptr1과 ptr2는 각각 가리키는 int형 동적 메모리가 각 소멸자에 의해 자동 삭제됨!
}
void main( )
{
DoSomething();
}
- 10
50
100
ptr1과 ptr2 객체는 auto_ptr 클래스와 shared_ptr 클래스의 객체로 스마트 포인터라 합니다.
또 실제 포인터와 같은 인터페이스와 기능을 제공합니다.
2, auto_ptr과 shared_ptr의 비교
auto_ptr 객체와 shared_ptr 객체의 가장 큰 차이점은
auto_ptr 객체는 단 하나의 객체만이 동적 메모리 객체(실제 객체)를 가리킬 수 있습니다. (소유권 이전이라 합니다.)
shared_ptr 객체는 레퍼런스 카운트를 이용하여 여러 객체가 동적 메모리 객체(실제 객체)를 가리킬 수 있습니다.
아래는 auto_ptr와 shared_ptr의 차이점을 보입니다.
#include <iostream>
#include <memory>
#include <boost/shared_ptr.hpp>
using namespace std;
using namespace boost;
void DoSomething( )
{
auto_ptr<int> ptr_a1= auto_ptr<int>( new int(10) );
auto_ptr<int> ptr_a2= ptr_a1;
auto_ptr<int> ptr_a3= ptr_a2;
shared_ptr<int> ptr_s1= shared_ptr<int>( new int(50) );
shared_ptr<int> ptr_s2= ptr_s1;
shared_ptr<int> ptr_s3= ptr_s2;
int *ptr_1 = new int(100);
int *ptr_2 = ptr_1;
int *ptr_3 = ptr_2;
//cout << *ptr_a1<<','<<*ptr_a2<<','<<*ptr_a3 << endl; // 오류(한 객체만이 동적 메모리 소유)
cout << *ptr_s1<<','<<*ptr_s2<<','<<*ptr_s3 << endl;
cout << *ptr_1<<','<<*ptr_2<<','<<*ptr_3 << endl;
delete ptr_1;
// ptr1과 ptr2는 가리키는 int형 동적 메모리가 각 소멸자에 의해 자동 삭제됨!
}
void main( )
{
DoSomething();
}
- 10,... 오류...
- 50,50,50
100,100,100
그래서 실제 포인터와 유사한 스마트 포인터는 shared_ptr입니다. STL 컨테이너 등에 auto_ptr을 사용하면 대박이 나겠죠??? ㅡㅡ?
아래 그림을 참고하세요.
다음 예제는 객체형(Point 객체)을 사용하는 예제입니다.
#include <iostream>
#include <memory>
#include <boost/shared_ptr.hpp>
using namespace std;
using namespace boost;
class Point
{
private :
int x, y;
public :
explicit Point(int _x=0, int _y=0) : x(_x), y(_y) { cout <<"Point()"<<endl; }
~Point( ) { cout <<"~Point()" <<endl; }
void Print( )const
{
cout << x <<", " << y << endl;
}
};
void DoSomething( )
{
auto_ptr<Point> ptr_a1= auto_ptr<Point>( new Point(2, 3) );
auto_ptr<Point> ptr_a2= ptr_a1;
auto_ptr<Point> ptr_a3= ptr_a2;
shared_ptr<Point> ptr_s1= shared_ptr<Point>( new Point(5, 5) );
shared_ptr<Point> ptr_s2= ptr_s1;
shared_ptr<Point> ptr_s3= ptr_s2;
Point *ptr_1 = new Point(10, 20);
Point *ptr_2 = ptr_1;
Point *ptr_3 = ptr_2;
(*ptr_a3).Print();
(*ptr_s3).Print();
(*ptr_3).Print();
ptr_a3->Print();
ptr_s3->Print();
ptr_3->Print();
delete ptr_1;
// ptr1과 ptr2는 가리키는 int형 동적 메모리가 각 소멸자에 의해 자동 삭제됨!
}
void main( )
{
DoSomething();
}
- Point()
Point()
Point()
2, 3
5, 5
10, 20
2, 3
5, 5
10, 20
~Point()
~Point()
~Point()
ptr_a3, ptr_s3, ptr_3 모두 객체의 주소를 가리키는 포인터이므로 Print() 멤버함수 호출 인터페이스가 같습니다.
또 Point 객체가 생성될 때 한 번의 생성자와 소멸될 때 한 번의 소멸자가 호출됩니다.
아래 그림을 참고하세요.
다음은 동적 객체를 직접 삭제하는 예제입니다.
#include <iostream>
#include <memory>
#include <boost/shared_ptr.hpp>
using namespace std;
using namespace boost;
class Point
{
private :
int x, y;
public :
explicit Point(int _x=0, int _y=0) : x(_x), y(_y) { cout <<"Point()"<<endl; }
~Point( ) { cout <<"~Point()" <<endl; }
void Print( ) const
{
cout << x <<", " << y << endl;
}
};
void DoSomething( )
{
auto_ptr<Point> ptr1= auto_ptr<Point>( new Point(2, 3) );
shared_ptr<Point> ptr2= shared_ptr<Point>( new Point(5, 5) );
Point *ptr3 = new Point(10, 20);
ptr1.reset(); //직접 동적 객체(Point) 삭제
ptr2.reset(); //직접 동적 객체(Point) 삭제
delete ptr3;
cout << "== something ==" <<endl;
}
void main( )
{
DoSomething();
}
- Point()
Point()
Point()
~Point()
~Point()
~Point()
== something ==
원하는 시점에 직접 객체를 삭제할 수 있습니다.
-출처 : http://coolprogramming.springnote.com/pages/3994205