반응형

http://blog.naver.com/cyberyanne/40107196465


다음과 같은 코드에서 Smart Pointer를 사용할 수 있을까?


class  Object
{
public:
      boost::shared_ptr<Object>  methodA(int value)
      {
           if(value == 0 )
               return this;  <-- 문제 코드.
           else
               return member;
       }

private:
       boost::shared_ptr<Object>    member;
}

위 코드에서 methodA(value)는 입력 매개 변수값에 따라 자기 자신을 리턴하거나, 
아니면 자기가 가지고 있는 member의 값을 리턴한다. member도 smart pointer로 
정의되어 있죠.

자, 이 경우 member를 리턴하는 것은 별 문제가 안됩니다. 
문제가 되는 경우는 자기 자신을 리턴해야 하는 경우입니다.

{
       boost::shared_ptr<Object>   pObj( new Object ), pObj2;
       
       pObj2 = pObj->methodA(0);
}

case 1. methodA()에서 컴파일 에러를 막기 위해서 boost::shared_ptr<Object>(this) 값을 
           리턴하는 경우를 생각해봅시다. 이렇게 되면, 위 App code에서 pObj, pObj2가 
           같은 오브젝트를 가리키는 서로 다른 2개의 smart pointer가 됩니다. 따라서
           메모리 객체가 2번 지워지는 에러가 발생합니다.

case 2. 그렇다고 "this"를 그대로 리턴할 수도 없습니다. 컴파일 에러가 나니까요.

case 3. Object가 스스로를 가리키는 smart pointer "self"를 가지게 하고, 이 값을 methodA()를
           통해서 리턴할 수도 있습니다. 하지만 이렇게 되면 해당 오브젝트는 자기 순환 참조를 하게
           되어 메모리 릭으로 남습니다. (use_count가 0이 될 수가 없습니다.)

이 문제를 해결하기 위해서 이리저리 자료를 찾아보고, 고민을 해봤는데, 
결론은 "shared_ptr<T>은 사용할 수 없다" 입니다.

대신, boost::intrusive_ptr<T>을 사용하면 이 문제를 해결할 수 있습니다.
intrusive_ptr<T>는 기본적으로 shared_ptr<T>와 사용법은 비슷하나 Reference Count를
메모리 객체가 직접 관리해야 하는 점이 다릅니다. shared_ptr<T>의 경우, 포인터를 감싸는
별도의 구조체를 자동으로 생성하고 거기에서 reference count를 관리하는데, intrusive_ptr<T>은
Object가 제공하는 Reference Counter 인터페이스를 이용합니다. 








http://kksuny.tistory.com/15


ntrusive_ptr 은 shared_ptr 과 마찬가지로 참조 카운팅 방식의 스마트 포인터다.

그러나 intrusive_ptr은 reference count 를 스마트 포인터에서 관리되는 객체에서 직접 관리한다.

intrusive_ptr 객체는 intrusive_ptr_add_ref 함수를 이용해 reference count 를 증가시키고

반대로 intrusive_ptr_release 함수로 감소시킨다.

intrusive_ptr_release 함수 에서는 reference count가 0이 될때 관리되는 객체를 파괴시켜야 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class MyClass;
void intrusive_ptr_add_ref(MyClass* p);
void intrusive_ptr_release(MyClass* p);
 
class MyClass
{
public:
    MyClass():m_refCount(0){}
    ~MyClass(){}
 
    friend void intrusive_ptr_add_ref(MyClass* p)
    {
        p->m_refCount++;
    }
 
    friend void intrusive_ptr_release(MyClass* p)
    {
        if(--(p->m_refCount) <= 0)
        {
            delete p;
        }
    }
private:
    long m_refCount;
};

intrusive_ptr 을 사용하는 주된 이유:

  • Some existing frameworks or OSes provide objects with embedded reference counts;
  • The memory footprint of intrusive_ptr is the same as the corresponding raw pointer;
  • intrusive_ptr<T> can be constructed from an arbitrary raw pointer of type T *.

shared_ptr보다 intrusive_ptr이 사용 요구에 맞는 것인지 명확하지 않다면 일반적으로, 먼저 shared_ptr 기반의 디자인을 시도한다.







http://blog.naver.com/cyberyanne/40107424728



boost::intrusive_ptr<T>는 boost 패키지에서 제공하는 또 다른 형태의 Smart Pointer입니다.
이전 글에서 설명한 boost::shared_ptr<T>는 smart pointer가 스스로 reference count를 관리했지만,
intrusive_ptr<T>는 reference count 관리를 타겟 메모리 객체에 맡깁니다. 즉, Reference count는
메모리 관리의 대상이 되는 객체에서 직접하고, intrusive_ptr<T>는 그 객체가 제공하는 Reference
count 기능을 빌려쓰는 겁니다. 그러면 메모리 객체와 intrusive_ptr<T> 사이를 연결해 주는
매개체가 있어야 겠죠. intrusive_ptr<T>는 다음의 두 함수를 통해 메모리 객체를 관리합니다.

void    intrusive_ptr_add_ref(Object *a_pObject) 
void    intrusive_ptr_release(Object *a_pObject)

예를 하나 들어보죠.
아래 클래스는 관리의 대상이 되는 Object를 정의합니다. 
보시면 Reference Count 인터페이스가 정의되어 있습니다.

class Object 
{
public:
// Constructor.
Object(void) : m_iRefCount(0) {};
virtual ~Object(void) {};

// Ref count manager.
void    inc_ref(void) { m_iRefCount++; };
void    dec_ref(void) { m_iRefCount--; };
void    get_ref(void) { return m_iRefCount; };

private:
int      m_iRefCount;
}

boost::intrusive_ptr<T>는 이전에 설명한 shared_ptr<T>와 동일한 방식으로 사용합니다.

{
boost::intrusive_ptr<Object>       sp1 = boost_intrusive_ptr<Object>(new Object);
boost::intrusive_ptr<Object>       sp2;

sp2 = sp1;
...
}

그리고 intrusive_ptr<T>와 Object를 연결하는 두 함수는 다음과 같이 제공되어야 합니다.

void     intrusive_ptr_add_ref(Object *a_pObject)
{
a_pObject->inc_ref();
}

void     intrusive_ptr_release(Object *a_pObject)
{
a_pObject->dec_ref();
if( a_pObject->get_ref() <= 0 )
delete a_pObject;
}

boost::intrusive_ptr<T>는 타겟 객체에 Reference count를 증가시킬 때, intrusive_ptr_add_ref()
함수를 호출하고, Reference count를 감소시킬 때 intrusive_ptr_release()를 호출합니다. 따라서
이 두 함수를 사용자가 제공해 주지 않으면 링크 에러가 발생하게 됩니다.

intrusive_ptr<T>는 어떤 경우에 유용할까요?

1. 기존 코드에 smart pointer를 입히는 경우입니다. 이미 예전 코드에 Reference count
   메커니즘이 적용되어 있는 경우, intrusive_ptr<T>을 이용하여 쉽게 코드를 refactoring
   할 수 있습니다.

2. Object가 자기 자신(this)에 대한 smart pointer를 리턴해야 하는 경우입니다.
    shared_ptr<T>는 이 상황을 처리하지 못합니다. (이전 글 참조)

3. ...

boost 패키지 문서에서는 가급적이면 shared_ptr<T>를 사용하라고 권고하고 있습니다.
하지만, 위에서 나열한 경우라면 intrusive_ptr<T>를 사용하는 것이 좀 더 나을 수 있습니다.

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost :: property_tree  (0) 2014.07.04
xml_parser.hpp, json_parser.hpp  (0) 2014.06.23
boost::pool  (0) 2013.05.11
boost::dynamic_bitset  (0) 2013.03.08
boost::boost::unordered_map, unordered_set  (0) 2013.03.02

+ Recent posts