Sunday, August 31, 2014

C++ Smart Pointers

C++ smart pointers are not a feature of the C++ language put a utilization of the language.  Consider the function below, which is translation of the C way of handling allocated resources:
bool function()
{
    Class *a {new Class};
    // ... do some work ...
    if (error)
    {
        delete a1;
        return false;
    }
    Class *b {new Class};
    // ... do some more work ...
    if (error)
    {
        delete b;
        delete a;
        return false;
    }
    // ... do final work ...
    delete b;
    delete a;
    return true;
}
Care must be taken to release the resources that were allocated to prevent memory leaks.  This puts the burden on the programmer to make sure resources are released.  Consider that if the class instances were local variables, their destructors would be called automatically when they go out of scope.  This is the basic idea of a smart pointer, consider this simple smart pointer class:
class SmartPtr
{
    Class *ptr;    // hold pointer to allocated resources
public:
    SmartPtr(Class *p) : ptr {p} {}
    ~SmartPtr() { delete ptr; }
    const Class *pointer() const { return ptr; }
};
The class holds the pointer to the allocated resource.  When the smart pointer instance goes out of scope, its destructor will release the resource it is holding.  The smart pointer provides access to the pointer it is holding.  This class can be made more elaborate and convenient (for example, allowing the pointer to be replaced, allowing the pointer to be cleared, providing the indirection and arrow operators so that it behaves like a pointer, etc.), but this definition is sufficient to show the basic concept of smart pointers.  The original function can be rewritten as:
bool function()
{
    SmartPtr a {new Class};
    // ... do some work ...
    if (error)
    {
        return false;
    }
    SmartPtr b {new Class};
    //
... do some more work ...
    if (error)
    {
        return false;
    }
    //
... do final work ...
    return true;
}
Note that it is no longer necessary to release the resources.  The new calls in the first function are known as naked, each of which requires a corresponding naked delete.  In the second function, the smart pointers hold the allocated resources (the new is enclosed).  When the smart pointer goes out of scope, it destructor is called releasing the resource.

Fortunately, very elaborate smart pointer classes have already been implemented.  In the C++11 version of the STL, there is the std::unique_ptr class, which is a more elaborate implementation of the class above.  Qt has the similar QScopedPointer class.

The C++11 STL also has the std::shared_ptr class, which is a smart pointer that can be shared.  These have a use count, which is incremented each time the pointer is copied (for example, put into a different list or stack).  When one of the copies is deleted, the use count is decremented.  When the use count reaches zero, the resource is automatically released.  Qt has the similar QSharePointer class.  These shared smart pointers will be used for the tokens, which get shared (in the RPN output list, done stack, holding stack, pending parentheses token, etc.).