반응형

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();
}

  1. 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();
}
  1. 10,... 오류...
  2. 50,50,50
    100,100,100

그래서 실제 포인터와 유사한 스마트 포인터는 shared_ptr입니다. STL 컨테이너 등에 auto_ptr을 사용하면 대박이 나겠죠??? ㅡㅡ?

아래 그림을 참고하세요.

 auto_ptr,shared_ptr(1).png

 

 

다음 예제는 객체형(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();
}
  1. 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 객체가 생성될 때 한 번의 생성자와 소멸될 때 한 번의 소멸자가 호출됩니다.

 

아래 그림을 참고하세요.

auto_ptr,shared_ptr2.png 

 

 

다음은 동적 객체를 직접 삭제하는 예제입니다.

 #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();
}
  1. Point()
    Point()
    Point()
    ~Point()
    ~Point()
    ~Point()
    == something  ==

 원하는 시점에 직접 객체를 삭제할 수 있습니다.

 

-출처 : http://coolprogramming.springnote.com/pages/3994205 


반응형

'SW개발' 카테고리의 다른 글

[CB Specification]  (0) 2013.01.16
[LINUX][특정 사용자 연결 종료]  (1) 2012.11.30
[예약 실행 crontab]  (0) 2012.11.27
[SIM Field for SMS & CBS]  (0) 2012.11.21
[Linux]심볼릭 링크&하드 링크  (2) 2012.11.20
[3GPP2]  (0) 2012.09.03
[QXDM] [로그 저장하고 불러오기]  (2) 2012.08.24
[리눅스 쉘(Shell) 스크립트]  (5) 2012.08.17
[Linux와 Shell]  (0) 2012.08.14
[VI 글자 색상 바꾸기]  (2) 2012.08.13

+ Recent posts