Reliable Software Logo
 Home  >  C++ Resources  >   Resource Management  >   Smart Pointers

Strong Pointers and Resource Management in C++

Smart Pointers

We haven't talked yet about the most common type of resource--an object allocated using operator new and afterwards accessed through a pointer. Should we, for each type of object, define a separate encapsulator class? As a matter of fact, the C++ standard library already has a template class, called the auto_ptr, whose purpose is to provide such encapsulation. I'll come back to auto_ptr later, but for now let's focus on one concept at a time. I'd like to start with something very inflexible but foolproof. Look at this smart pointer template--it's so rigid it can't even be instantiated.

template <class T>
class SPtr
{
public: 
    ~SPtr () { delete _p; } 
    T * operator->() { return _p; } 
    T const * operator->() const { return _p; } 
protected: 
    SPtr (): _p (0) {} 
    explicit SPtr (T* p): _p (p) {} 
    T * _p;
};

Why did I make the constructors of SPtr protected? I had to, if I wanted to follow the first rule of acquisition. The resource--in this case an object of class T--must be allocated in the constructor of the encapsulator. But I can't simply call new T, because I have no idea what arguments the constructor of T requires. Since, in principle, each T has a different constructor; I need to define a different encapsulator for it. Having a template, though, helps a lot. For each new class, I can define a new encapsulator that inherits the entire behavior from the appropriate SPtr and simply provides a specialized constructor.

class SItem: public SPtr<Item>
{
public:
    explicit SItem (int i) 
    : SPtr<Item> (new Item (i)) {}
};

Is creating a new smart pointer class for each type really worth the effort? Frankly--no! It has a great pedagogical value, but once you've learned how to follow the first rule of acquisition, you can relax it and start using the advanced technique. The technique is to make the constructor of SPtr public, but use it only for direct resource transfer. By that I mean--use the result of operator new directly as an argument to the constructor of SPtr. Like this.

SPtr<Item> item (new Item (i));

This method obviously requires more self-control, not only from you but also from every member of your programming team. They have to swear not to use this public constructor for any other purpose, but for direct resource transfer. Fortunately, this rule is easy to enforce. Just grep the sources from time to time for all occurrences of new.


NextNext: Resource Transfer