Click here to Skip to main content
Click here to Skip to main content

A Simple Smart Pointer

By , 11 Jan 2000
 
  • Download demo project - 19 Kb
  • Download source files - 1.6 Kb
  • Here is another smart pointer implementation. It's as easy as it gets.

    How to use it

    #include "/libs/idlsoft/smartptr.h"
    using namespace idllib;
    // in a body
        SmartPtr<CMyObject> ptr1(new CMyObject);  // construct from a pointer
        SmartPtr<CMyObject> ptr2(ptr1);   // construct from a smart pointer
        SmartPtr<CMyObject> ptr3;         // construct an empty one
        ptr3 = new CMyObject;                   // assign a pointer
        ptr1 = ptr3;                            // assign a smart pointer
        ptr1->method1();                     // call a method
        ptr2 = NULL;
        // etc ...    
    // in a function call
        void f(CMyObject *ob);                   // function declaration
        ...
        SmartPtr<CMyObject> ptr1(new CMyObject);
        f(ptr1);                                // function call
    // as a return value
        SmartPtr<CMyObject> f1()
        {
            return SmartPtr<CMyObject>(new CMyObject);
        }
        ...
        SmartPtr<CMyObject> ptr;
        ptr = f1();
    

    That's it!

    No need to worry about freeing the pointer, the object is deleted through a standard reference-counting mechanism.

    SmartPtr is the only class you really need here. It can point to anything that was allocated by the new operator.

    How NOT to use it

        // 1.
        SmartPtr<CMyObject> ptr;
        CMyObject ob;
        ptr = &ob;  // DON'T ! only memory allocated by new operator should be used
        // 2.
        SmartPtr<CMyObject> ptr1, ptr2;
        CMyObject *o2 = new CMyObject;
        ptr1 = o2;
        ptr2 = o2;  // DON'T ! unless CMyObject implements IRefCount
                    // try to use ptr1 = ptr2 instead, it's always safe;
    

    How it is implemented

    SmartPtr holds a pointer to a reference counting object. Every time we assign a value to SmartPtr it decrements the reference count on the current object and increments it for the new one. The reference counter for its part would delete the allocated object if the reference drops to zero.

    The reference counter can be either part of the allocated object (when we implement IRefCount) or a separate object (SmartPtr::__RefCounter) that holds a pointer to it.

    See next section for details.

    How to optimize memory usage

    In order to count references to the allocated object SmartPtr creates a special object, which means two memory allocations instead of one. If you want to optimize the memory usage just implement IRefCount in your class. You can do it yourself or use IRefCountImpl:

        class CMyObject : public CObject, public IRefCountImpl<CMyObject> {
        ...
        };
    
    In this case SmartPtr will use the built-in counter instead of a sparate one.

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here

    About the Author

    Sandu Turcan
    United Kingdom United Kingdom
    Member
    No Biography provided

    Sign Up to vote   Poor Excellent
    Add a reason or comment to your vote: x
    Votes of 3 or less require a comment

    Comments and Discussions

     
    You must Sign In to use this message board.
    Search this forum  
        Spacing  Noise  Layout  Per page   
    Generaloptimization suggestionmemberShumy1 Dec '05 - 13:17 
    why not modify this
     
    void __Assign(IRefCount *refcount)
    {
    if(refcount!=NULL) refcount->__IncRefCount();
    IRefCount *oldref = __m_refcount;
    __m_refcount = refcount;
    if(oldref!=NULL) oldref->__DecRefCount();
    }
    to this
     
    void __Assign(IRefCount *refcount)
    {
    if(refcount!=NULL) refcount->__IncRefCount();
    if(__m_refcount!=NULL) __m_refcount->__DecRefCount();
    __m_refcount = refcount;
    }
     
    one less push and pop to do in the stack program!Sniff | :^)
    Generaldynamic_cast&lt;...&gt; (corrected)memberitaifrenkel3 Jan '04 - 21:25 
    I would like to downcast a smartpointer. For example:
     
    class A : public IRefCountImpl<A>
    class B : public A
     
    class B does not implement IRefCount<B> (but rather IRefCount<A>) and that causes many errors when casting the smart pointer.
     
    I tried to use Visual C++.NET 2003 covariant inheritance and virtual inheritance, but it did not compile. Any suggestions ?
     
    class A : public virtual IRefCountImpl<A>
    class B : public virtual A , public virtual IRefCountSubImpl<B,A>
     
    template <class T,class BT> class IRefCountSubImpl : public virtual IRefCountImpl<BT> {
          protected:
     
         virtual void __IncRefCount()
          {
              BT::__IncRefCount();
          }
          virtual void __DecRefCount()
          {
              BT::__DecRefCount();
          }
        
         //Overrides BT* GetPtr() const
         //Remember: Virtual base classes are not supported as covariant return types.
         virtual T * GetPtr() const
          {
                return ((T *)this);
          }
    };
    Generaldynamic_cast&lt;...&gt;memberitaifrenkel3 Jan '04 - 21:23 
    I would like to downcast a smartpointer. For example:
     
    class A : public IRefCountImpl
    class B : public A
     
    class B does not implement IRefCount (but rather IRefCount
    ) and that causes many errors when casting the smart pointer.
     
    I tried to use Visual C++.NET 2003 covariant inheritance and virtual inheritance, but it did not compile. Any suggestions ?
     
    class A : public virtual IRefCountImpl

    class B : public virtual A , public virtual IRefCountSubImpl
     
    template class IRefCountSubImpl : public virtual IRefCountImpl {
    protected:
     
    virtual void __IncRefCount()
    {
    BT::__IncRefCount();
    }
    virtual void __DecRefCount()
    {
    BT::__DecRefCount();
    }

    //Overrides BT* GetPtr() const
    //Remember: Virtual base classes are not supported as covariant return types.
    virtual T * GetPtr() const
    {
    return ((T *)this);
    }
    };
    Generalsuggestionmemberovolok27 Nov '03 - 16:56 
    i suggest to add "const T * operator ->() const" to class SmartPtr
    as now it is illegal to use operator-> on const SmartPtr object
    Generalnitpick, optimization, and complimentmemberpeterchen30 Sep '03 - 11:34 
    a) nitpick: Identifiers containing two successive underscores (or start with one) are reserved for compiler use
     
    b) Since you template over T, you dont need to make the methods virtual
    (you wouldn't even need a base class, just require that the very methods are there)
     
    c) I like your solution for classes that do not implement the refcounting interface Wink | ;)

     

    "Vierteile den, der sie Hure schimpft mit einem türkischen Säbel."

    sighist | Agile Programming | doxygen

    Generaluse in multiple Threads - thread safetymemberThomas George25 Jan '02 - 8:38 
    I have a thread pool class that has a member function
    ProcessInThread(void* p)
    This will get invoked in another thread.
     
    I made a class
    CCommandWrapper
    {
    public:
     SmartPtr &lt CCommand &gt m_command;
     SmartPtr &lt CMyObject &gt m_object;
    }
    
     

    In the application.
    CMyObject::process(SmartPtr &lt CCommand &gt pcommand)
    {
     CCommandWrapper* pwrapper = new CCommandWrapper;
     pwrapper->m_command = pcommand;
     pwrapper->m_object = this; // CMyObject implements IRefCountImpl
     GetThreadPool()->ProcessInThread((void*)pwrapper);
    }
    
     

    In the thread, I do
    int ThreadProc(void* p)
    {
     CCommandWrapper* pcmd = (CCommandWrapper)p;
     pcmd->m_object->processcommand(m_command);
    }
    
    When the ThreadProc quits, there is an access violation occasionally in the SmartPtr's DestroyRef.
     
    Thomas
    GeneralRe: use in multiple Threads - thread safetymemberThomas George25 Jan '02 - 8:50 
    an update .. the problem seems to be not occurring when I changes the __DecRefCount() to if(__m_counter == 0) { __DestroyRef(); } instead of
    if(__m_counter <= 0) { __DestroyRef(); } . I also changed the increment and decrement to use the InterlockedIncrement and InterlockedDecrement functions.
     
    Why would the __m_counter ever become a negative number? If you have any clue as to what might be happening, please reply...
     
    The class is very good and makes a lot of things very very easy.
     
    Thank you.
     

    Thomas
     

    GeneralRe: use in multiple Threads - thread safetysussAnonymous6 Aug '02 - 11:57 

     
    You have to remember that
    in a multithreaded environment things happen concurrently.
    You are not guaranteed the order of code execution.
    Unless you know an operation is atomic (always completed by a thread before execution moves to another thread) it can be interrupted before its
    completed.
     

    Imagine the following scenario:
    __m_counter = 1
     
    Thread A:
    executes __m_counter--;
     
    Now __m_counter equals 0
     
    At this point the task scheduler stops thread A and activates thread B
     
    Thread B:
    executes __m_counter--;
     
    Now __m_counter equals -1
     
    At this point both threads will test the condition
    if(__m_counter<=0)
    and determine it to be true and will go on and call
    __DestroyRef()
     
    Resulting in a double deletion of the same memory pointer.
     
    changing the line to:
    if(__m_counter == 0)
    is not a good solution because
    it won't solve all the cases.
    You need to make this operation:
    __m_counter--
    and
    if(__m_counter==0)
    __DestroyRef()
     
    into an atomic operation.
    You can do this by using the various synchronization objects the
    win32 API has to offer like mutex/critical section and InterlockedDecrement.
     

     


    GeneralRe: use in multiple Threads - thread safetymemberThomas George6 Aug '02 - 13:08 
    Thank you very much for the reply.
    GeneralRe: use in multiple Threads - thread safetymemberSandu Turcan6 Aug '02 - 15:19 
    Thomas George wrote:
    In the thread, I do
    int ThreadProc(void* p)
    {
    CCommandWrapper* pcmd = (CCommandWrapper)p;
    pcmd->m_object->processcommand(m_command);
    }

    I'm sorry I don't have the answer to your question, at least not yet. I can't possibly think of a reason why the counter would ever become negative. I'll try to figure it out, in the mean time I have a few questions about your sample:
    What's m_command?
    And why isn't pcmd freed?
    And why is it (CCommandWrapper)p and not (CCommandWrapper *)p?

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Permalink | Advertise | Privacy | Mobile
    Web04 | 2.6.130523.1 | Last Updated 12 Jan 2000
    Article Copyright 2000 by Sandu Turcan
    Everything else Copyright © CodeProject, 1999-2013
    Terms of Use
    Layout: fixed | fluid