Smart Pointers

Problems with pointers:

1. Not initialized by constructors, so uninitialized pointers can be used (dangling pointer problem)

2. Not disposed of by destructors, so resources may not be deallocated (memory leak problem).

Solution: use of smart pointers, also called counted pointers. A smart pointer is a wrapper class for pointers. Since these are objects, they are initialized using constructors and their destructors are automatically called when go out of scope.

They also need to behave like ponters, so they need to overload the * and -> operators.

An example of such a wrapper class:

Declarations (header file)


#ifndef  SMARTPOINTER_H
#define  SMARTPOINTER_H 
  template< typename Body >
  /* Template requirements for Body:
   *   None
   */
  class Handle {
  public:
    explicit Handle(Body* = 0);
    Handle(const Handle&);
    ~Handle();
    Handle& operator=(const Handle&);
    Body* operator->();
    Body& operator*();
  private:
    Body* bridge_;
    int* counter_;
  };
#endif

Implementation (source file)


#include "smartpointer.h"

  template< typename Body >
  Handle< Body >::Handle(Body* b) : bridge_(b) { 
    counter_ = new int(1);
  }

  template< typename Body >
  Handle< Body >::Handle(const Handle< Body >& h) : bridge_(h.bridge_) {
    counter_ = h.counter_;
    (*counter_)++;
  }

  template< typename Body >
  Handle< Body >::~Handle< Body >() {
    if(--counter_ == 0) {
      delete counter_;
      delete bridge_;
    }
  }

  template
  Handle< Body >& Handle< Body >::operator=(const Handle< Body >& rhs)  {
    if(this == &rhs || bridge_ == rhs.bridge_)
      return *this;

    if(--counter_ == 0) { // left-hand side has no references
      delete counter_;
      delete bridge_;
    }

    bridge_ = rhs.bridge_;
    counter_ = rhs.counter_;
    (*counter_)++;
    return *this;
  }

  template< typename Body >
  Body* Handle::operator->() {
    return bridge_;
  }
 
  template< typename Body> 
  Body& Handle< Body >::operator*() {
    return *bridge_;
  }

Client Code (using an appropriate Point class)

  Handle< Point > hp1(new Point(1, 2));
  cout << hp1->getX() << endl;  // hp1.operator->()->getX();
  Handle< Point > hp2(hp1); // share points
  Handle< Point > hp3(new Point(3, 4));
  hp3 = hp2;    // deallocate point (3, 4)
  cout << hp2->getY() << " " << hp3->getY() << endl;