Smart pointer with Reference Counting

Discussion in 'C++' started by Mridula, Mar 5, 2009.

  1. Mridula

    Mridula New Member

    Joined:
    Mar 5, 2008
    Messages:
    316
    Likes Received:
    19
    Trophy Points:
    0
    Occupation:
    S/w proffessional
    Location:
    Bangalore

    Introduction



    This article talks a little bit about Smart Pointer conepts and then move on to Reference Counting. Then there is a smaple code to implement the same.

    Background



    Smart pointer or auto-pointer is a simple wrapper around a regular pointer, provides all meaningful operations to it's embedded piointer (derefencing and indirection).

    It's smartness lies in it's destructor which takes care of deleting it's embedded pointer and makes user not to worry from freeing his/her dynamically allocated memory.

    The fundamental logic behind designing Smart Pointer is that the Stack is safer than Heap. Variables on the Stack are automatically destructed when they go out of scope. Whereas Variables on Heap are freed only by an explicit call to Delete.

    So, the trick is to represent Heap based object, accessed through a dumb pointer by a stack based object and when this stack based object goes out of scope, it's Destructor is called, which in turn takes care of freeing the memory associated with the dumb pointer.

    For Example here instead of writing

    Code:
    int main()
    {
      MyClass *p (new MyClass);
      p->DoSomething();
      delete (p);
    }
    
    We can write by trusting Smart Pointer or Auto Pointer, that p gets deleted on after it comes out of the scope :

    Code:
    int main()
    {
      MyClass *p (new MyClass);
      p->DoSomething();  
    }
    
    Though Smart Pointer is quite smart, but there is a below draw back with this:

    See the below code

    Code:
    int main()
    {
      MyClass *p = new (MyClass);
      MyClass *q = p;
      p->DoSomething();  
      delete (p);
      
      q->DoSomething();  // q is now a dangling pointer
    }
    
    i.e. When we assign pointer p to q as in the above code and then delete pointer p, it simply deletes the object pointed by pointer "p", irrespective of tehre is another pointer "q" refrencing to it and then currupts the heap.

    There are set of solutions to this problem. But we can solve this in a simple way by providing refrence counting facility to the embedded pointer.

    Reference Counting does maintain a count of all the pointers that are referencing to the object and deletes the object only when this Reference Count becomes Zero or when the last object which is using this pointer gets destroyed.

    Also you can use reference counting in any class that manages a shared resource, and not just for smart pointers or auto pointers.

    Logic behind Refrence Counting implementation is as below:

    1. When the object that is being managed is created, its reference count
    is set to one.

    2. When the managing object - the smart pointer - is copied or assigned,
    the reference count is incremented.

    3. When a smart pointer is destructed, as when a member variable's owning
    object is destructed, or a value goes out of scope, or an allocated
    smart pointer is deleted, the reference count is decremented.

    4. Once when the refCount becomes zero, then the pointer gets deleted.

    This is also called as Shared Ownership Pattern.

    Here is a sample code which implements Smart Pointer with Reference Conting:

    The code



    Here class Pointer is a Real Pointer, where-as class Smart Pointer is a wrapper around Pointer.

    Code:
    #include <iostream.h>
    
    class Pointer 
    {
      public:
    
       	//standard construction and destruction:
       	Pointer () {
                      cout<<"Pointer::default constructor = \n";
                    }
        
       	Pointer (const Pointer& rhs) {
                                        cout<<"Pointer::copy constructor = \n";
                                        myVal_ = rhs.myVal_;
                                      }
                                      
       	Pointer& operator = (const Pointer& rhs) {
                                                    cout<<"Pointer::operator = \n";
                                                    if(this != &rhs)
                                                    {
                                                      myVal_ = rhs.myVal_;
                                                      return (*this);
                                                    }
                                                  }
                                                  
       	~Pointer (void){
                          cout<<"Pointer::Destructor\n"; 
                        }
    
        //reference counting related methods
        void acquire(void){
                            ++refCount_;
                          } // increase refCount
        
        unsigned int release(void){
                              return(--refCount_);
                            } //decrease refCount
        
        //accessor
        unsigned int count(void){
                            cout<<"Reference count value is ="<<refCount_<<"\n";
                            return (refCount_); //return current count
                          }
    
      private:
        
        //data
        int myVal_;
        unsigned int refCount_; // reference counting related data
    
    };    //   Pointer
    
    //****** Here is our own SmartPointer class for Pointer class ******
    
    class SmartPointer {
      public:
    
        //   standard construction and destruction:
        SmartPointer(Pointer *ptr):ptr_(ptr){ 
                                              cout<<"SmartPointer::default constructor = \n";
                                              ptr_->acquire();
                                             }
        
        SmartPointer(const SmartPointer &rhs):ptr_(rhs.ptr_){
                                                              cout<<"SmartPointer::copy constructor = \n";
                                                              ptr_->acquire();
                                                            }
        
        SmartPointer& operator = (const SmartPointer &rhs){
                                                            cout<<"SmartPointer::operator = \n";
                                                            if (this != &rhs)
                                                            {
                                                              ptr_->release();
                                                              ptr_ = rhs.ptr_;
                                                              ptr_->acquire();
      
                                                              return(*this);
                                                            }
                                                          }
    
        ~SmartPointer (void){
                              cout<<"SmartPointer::Destructor\n"; 
                              if (NULL != ptr_)
                              { if (0 == ptr_->release())
                                {
                                   ptr_->count();
    
                                   delete(ptr_);
                                   ptr_ = NULL;
                                }
                              }
                            }
    
        Pointer* operator -> (void) { 
                                      return (ptr_);
                                    }
    
        Pointer& operator * () const {
                                        return(*ptr_);
                                      }     
    
      private:
        Pointer * ptr_;
    };    //   SmartPointer
    
    // ******* client uses SmartPointer as a Stack Variable here ********
    int main()
    {
      {
        //sp1 acquires refCount now. so refCount = 1
        SmartPointer sp1 = SmartPointer( new Pointer());
        sp1->count();
        {
          //sp2 referes sp1 and acquires refCount now. so refCount = 2
          SmartPointer sp2 = sp1;
          sp1->count();
        } // at this point sp2 relases refCount. so refCount = 1
        
        sp1->count();
      } // at this point sp1 relases refCount. so refCount = 0 and so here the ptr_ gets deleted
      
      return(0);
    }
    
    The ouput:
    ----------
    Pointer::default constructor = 
    SmartPointer::default constructor = 
    Reference count value is =1
    SmartPointer::copy constructor = 
    Reference count value is =2
    SmartPointer::Destructor
    Reference count value is =1
    SmartPointer::Destructor
    Reference count value is =0
    Pointer::Destructor
    
    
     
  2. shabbir

    shabbir Administrator Staff Member

    Joined:
    Jul 12, 2004
    Messages:
    15,375
    Likes Received:
    388
    Trophy Points:
    83
    Article of the month competition nomination started here
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice