Pages

getteammates.com

Thursday, 5 February 2015

Shared and smart pointer implementation in c++


Introduction

Shared pointer is a class which can share the underlying data between object. This avoids deep copying and improves performance. It is also called as shallow copying.

Smart pointer is a class which manages the life time of the underlying pointer.

A simple smart pointer class

Lets create a simple base class for smart pointer class using c++ template so that we can store any type of data.
The basic idea of a shared pointer or a smart pointer is that actual data is stored separately and the shared pointer or smart pointer class will have a pointer to it.


For a very basic shared pointer class will have the data class as,
    class Data
    {
    public:
        int mRefCount;
        T mData;
    }; 

Let our class name be RSharedObject. Now lets declare the copy constructor and assignment operator function. The template parameter T is the actual pointer.

template < typename T >
class RSharedObject
{
protected:
    class Data
    {
    public:
        int mRefCount;
        T mData;
    };

public:
    RSharedObject()
     : mData(0)
    {}

    RSharedObject(RSharedObject const & o)
    {
        mData = 0;
        copy(o);
    }

    RSharedObject& operator=(RSharedObject const & o)
    {
        copy(o);
        return *this;
    }
    // ...
};

Let add referencing and dereferencing logic now to complete the implementation,
template <typename T >
class RSharedObject
{
protected:
    class Data
    {
    public:
        int mRefCount;
        T mData;
    };

public:
    RSharedObject()
     : mData(0)
    {}

    RSharedObject(RSharedObject const & o)
    {
        mData = 0;
        copy(o);
    }

    RSharedObject& operator=(RSharedObject const & o)
    {
        copy(o);
        return *this;
    }

    virtual ~RSharedObject()
    {
        dispose();
    }

protected:
    virtual T & data_p()
    {
        if (!mData) {
            create();
        }
        return mData->mData;
    }

    virtual const T & data_p() const
    {
        if (!mData) {
            const_cast *>(this)->create();
        }
        return mData->mData;
    }
    void copy(RSharedObject const & oth)
    {
        dispose();
        mData = oth.mData;
        ref();
    }

   void detach()
    {
        if (mData && mData->mRefCount > 1) {
            deref();
            mData = new Data(*mData);
            mData->mRefCount = 1;
        }
    }

private:
    void create()
    {
        mData = new Data();
        ref();
    }

    void dispose()
    {
        if (mData) {
            deref();
            if (mData->mRefCount == 0) {
                delete mData;
                mData = 0;
            }
        }
    }

    void ref()
    {
        if (mData) {
            ++mData->mRefCount;
        }
    }

    void deref()
    {
        if (mData) {
            --mData->mRefCount;
        }
    }

private:
    Data * mData;
};



Function data_p will be used to access the actual data from the derived classes.

Lets create a detachable shared object class. Detachable shared object class detaches itself from the underlying pointer data if required.

template <typename T >
class RDetachableRSharedObject: RSharedObject
{
protected:
    T & data_p()
    {
        this->detach();
        return RSharedObject::data_p();
    }

    const T & data_p() const
    {
        return RSharedObject::data_p();
    }
};

Then smart pointer class

We will create a base class for smart pointer so that we can have smart pointer class for both object and array.

This smart pointer base class will derive from our RSharedObject class.

template <typename A, typename D >
class RSmartPointerBase: public RSharedObject < A >
{
public:
    RSmartPointerBase(D * p)
    {
        this->data_p().mPtr = p;
        this->data_p().mOwn = true;
    }

    bool isNull() const
    {
        return data() == 0;
    }

    D * data()
    {
        return this->data_p().mPtr;
    }

    const D * data() const
    {
        return this->data_p().mPtr;
    }

    D * take()
    {
        this->data_p().mOwn = false;
        return this->data_p().mPtr;
    }

    D * operator->()
    {
        return data();
    }

    const D * operator->() const
    {
        return data();
    }

    D & operator*()
    {
        return *(data());
    }
    const D * operator*() const
    {
        return *(data());
    }
};
Lets now create the actual smart pointer,

template < typename D >
class RSmartPointerData
{
public:
    RSmartPointerData()
     : mOwn(true),
       mPtr(0)
    {}

    ~RSmartPointerData()
    {
        if (mOwn) {
            delete mPtr;
        }
    }

private:
    RSmartPointerData(RSmartPointerData const &);
    RSmartPointerData & operator=(RSmartPointerData const &);

public:
    bool mOwn;
    D * mPtr;
};

template < typename D >
class RSmartPointer: public RSmartPointerBase<RSmartPointerData<D>, D>
{
public:
    RSmartPointer(D * p=0)
     : RSmartPointerBase, D>(p)
    {}

    operator D*()
    {
        return this->data();
    }

    operator const D*() const
    {
        return this->data();
    }
};


Lets now create the actual smart array pointer,

template < typename D >
class SmartArrayPointerData
{
public:
    SmartArrayPointerData()
     : mOwn(true),
       mPtr(0)
    {}

    ~SmartArrayPointerData()
    {
        if (mOwn) {
            delete [] mPtr;
        }
    }

private:
    SmartArrayPointerData(SmartArrayPointerData const &);
    SmartArrayPointerData & operator=(SmartArrayPointerData const &);

public:
    bool mOwn;
    D * mPtr;
};

template <typename D >
class SmartArrayPointer: public RSmartPointerBase< SmartArrayPointerData<D>, D>
{
public:
    SmartArrayPointer(D * p=0)
     : RSmartPointerBase, D>(p)
    {}

    operator D*()
    {
        return this->data();
    }

    operator const D*() const
    {
        return this->data();
    }
};
I know it is more code and less document, but hopefully it helps.

Complete implementation can be found at https://github.com/trsquarelab/glexamples/blob/master/src/common/rsmart_pointer.h

1 comment:

  1. Great! Shared with my devs! thanks. Another question - is dataroom services your sphere of interest? Should I await for some reviews on this topic? Thanks in advance

    ReplyDelete