2011年2月9日 星期三

Boost::SmartPtr Sample,以ResourceManager為例

Dear All:
最近這幾天玩了一下Boost::SmartPointer,感覺還不錯用,順手寫了些Sample Code,主要的內容是說:一各ResourceManager要如何精確管理Resource?確定Resource何時可以被release?換句話說,Resource在出生後傳遞給外界被使用,參考來參考去,Manager必須知道Resource到底已經被參考過幾次了,到這第一各想法就是Smart Pointer,藉由Smart Pointer本身的Reference Count即可解決問題所在。

當然我也是第一次使用SmartPointer,所以爬文少不了,對岸網友在一各論壇上寫了篇還不錯的教學,對新手來說相當有用可以看看:
http://www.usidcbbs.com/read-htm-tid-1978.html

國外這篇發表在stackoverflow的也不錯:
http://stackoverflow.com/questions/106508/what-is-a-smart-pointer-and-when-should-i-use-one

【附帶一提】
Manager會把有Resource的第一各Ref_Count,所以當Resource被Manager第一次產生時 or 不在有外界使用時,Ref_Count == 1,這樣的好處是Manager在檢查當Ref_Count == 1的時候可以清楚的知道Resource接下來是因該被刪除還是再保留一段時間後刪除,有就是Resource cache system的作用,如果沒記錯OGRE也是使用類似的做法。

來看Sample Code吧:
#include < iostream >
#include < map >
#include "shared_ptr.hpp"
#include "shared_array.hpp"

class Object
{
public:
    Object( int iID ) : m_iID(iID) {}
    virtual ~Object( void )
    { 
        m_iID = -1;
    }

    int getID( void ) { return m_iID; }

protected:
    int m_iID;
};

typedef boost::shared_ptr ObjectPtr;
class ObjectManager
{
   typedef std::map ObjectsMap;
public:
    ObjectManager( void ) : m_mapObjectPtrs() {}
    virtual ~ObjectManager( void )
    {
        // Check object's ref_count, if anyone is not 1, assert!!
        ObjectsMap::iterator ite;
        ObjectsMap::iterator iteEnd = m_mapObjectPtrs.end();
        for( ite=m_mapObjectPtrs.begin(); ite!=iteEnd; ++ite )
        {
            int iRefCount = ite->second.use_count();
            if( iRefCount != 1 )
            {
                std::cout << std::endl;
                std::cout << "WARRING: Object ID: "
                          << ite->second->getID()
                          << "Ref_count is not 1" << std::endl;
                assert( iRefCount == 1 );
            }
        }
    }

    ObjectPtr getObj( int iID )
    {
        ObjectsMap::iterator ite = m_mapObjectPtrs.find( iID );
        if( ite == m_mapObjectPtrs.end() )
        {
            m_mapObjectPtrs.insert( ObjectsMap::value_type( iID, ObjectPtr(new Object(iID)) ) );
            ite = m_mapObjectPtrs.find( iID );
        }
        return ite->second;
    }

protected:
    ObjectsMap m_mapObjectPtrs;
};

void testFunCallByValue( ObjectPtr spObj )
{
    std::cout << "spObj ID: "
              << spObj->getID()
              << " Ref_count: "
              << spObj.use_count() << std::endl;
}

void testFunCallByReference( ObjectPtr& spObj )
{
    std::cout << "spObj ID: "
              << spObj->getID()
              << " Ref_count: "
              << spObj.use_count() << std::endl;
}

void testFunCallByPointer( ObjectPtr* spObj )
{
    std::cout << "spObj ID: "
              << (*spObj)->getID()
              << " Ref_count: "
              << (*spObj).use_count() << std::endl;
}

void testFunSharedArray( void )
{
    // New object array which doesn't have default constructor;
    void* pObjectMemory = operator new[]( sizeof(Object)*5 );
    Object* pObjArray = static_cast<Object*> ( pObjectMemory );
    for( int i=0; i<5; i++ )
        new (&pObjArray[i])Object(i);

    // shared_array sample code:
    // all Objects will be managed by one shared_array
    boost::shared_array spaObjArray( pObjArray );
    std::cout << "shared_array Ref_count: " << spaObjArray.use_count() << std::endl;

    // shared_array will delete ObjectArray automatically!!
    // No need delete[] pObjectMemory;
}

void main( void )
{
    // Create instance of ObjectManager:
    ObjectManager* pObj_manager = new ObjectManager();;

    // Get Object from Manager:
    ObjectPtr spObj = pObj_manager->getObj(5);
    std::cout << "spObj ID: "
              << spObj->getID()
              << " Ref_count: "
              << spObj.use_count() << std::endl;

    // Testing functions:
    testFunCallByValue( spObj );     //Ref_Count will +1
    testFunCallByReference( spObj ); //Ref_Count will +0
    testFunCallByPointer( &spObj );  //Ref_Count will +0
    testFunSharedArray();

    // Release Object:
    spObj.reset();
    if( spObj == NULL )
        std::cout << "spObj == NULL" << std::endl;

    // Get another Object from Manager:
    spObj = pObj_manager->getObj(2);
    std::cout << "spObj ID: "
              << spObj->getID()
              << " Ref_count: "
              << spObj.use_count() << std::endl;

    // Delete manager:
    delete pObj_manager;
    pObj_manager = NULL;
    return;
}


以上的說明希望對"未來的我" or "正在閱讀的你"有幫助,謝謝!!

沒有留言:

張貼留言

LinkWithin

Related Posts Plugin for WordPress, Blogger...