[Qt-interest] Const correctness with QSharedPointer

Pavel Koshevoy pavel at aragog.com
Tue Dec 8 01:06:18 CET 2009


Colin Kern wrote:
> I'm going to hijack my own thread here, since I have another question
> about QSharedPointers.  Is there a way to maintain polymorphism when
> using QSharedPointers?  This code works:
>
> class A { };
> class B : public A { };
> void func(A* p) { };
> int main()
> {
>     B *p = new B();
>     func(p);
> }
>
> but this doesn't compile:
>
> #include <QSharedPointer>
> class A { };
> class B : public A { };
> void func(QSharedPointer<A> p) { };
> int main()
> {
>     QSharedPointer<B> p(new B());
>     func(p);
> }
>   

I have implemented a shared pointer class with behavior you are 
describing, so it is possible (and very useful).

In my implementation I have a template reference count class, 
parameterized by the base type of the objects you want to store.  The 
shared pointer class is parameterized by 2 types -- the concrete type of 
the object stored, and the base type.  The shared pointer class handles 
dynamic type conversion between pointer types if necessary (in a mutator 
constructor).  I will not provide a full implementation of these classes 
here, but I will include excerpts of relevant code. It works for me, use 
at your own risk, fill in the blanks as necessary.

template <typename TBase>
class CARefCount
{
public:
    // .. typical reference count API goes here (increment, decrement, 
getCount, isShared, virtual destructor, etc...)
  
private:
    // intentionally disabled:
    CARefCount (const CARefCount &);
    CARefCount & operator = (const CARefCount &);

protected:
    std::size_t m_refCount;

public:
    TBase * m_pointee;
};

template <typename TData, typename TBase = TData>
class CASharedPtr
{
    template <typename TCast, typename TCastBase> friend class CASharedPtr;
   
public:
    typedef TBase base_type;
    typedef TData value_type;

    explicit CASharedPtr (TData * realPtr):
        m_refCounter (new CountHolder())
    {
        m_refCounter->m_pointee = static_cast<TBase *>(realPtr);
        m_refCounter->AddReference ();
    }
   
    CASharedPtr (const CASharedPtr & fromSharedPtr):
        m_refCounter (fromSharedPtr.m_refCounter)
    {
        m_refCounter->AddReference ();
    }

    template <typename TFrom>
    CASharedPtr (const CASharedPtr<TFrom, TBase> & fromSharedPtr):
        m_refCounter (new CountHolder())
    {
        m_refCounter->AddReference ();
        *this = fromSharedPtr.cast<TData>();
    }
   
    ~CASharedPtr ()
    { m_refCounter->RemoveReference (); }
  
    // shared pointer assignment operator:
    CASharedPtr & operator = (const CASharedPtr & fromSharedPtr);

    // .. typical shared pointer API goes here (pointer conversion, 
comparison operators, dereference operators, etc...)

    // shared pointer type cast method:
    template <typename TCast>
    CASharedPtr<TCast, TBase> cast() const
    {
        TData * data = static_cast<TData *>(m_refCounter->m_pointee);
        TCast * cast = dynamic_cast<TCast *>(data);
        CASharedPtr<TCast, TBase> castPtr;
        if (cast)
        {
            delete castPtr.m_refCounter;
            castPtr.m_refCounter = m_refCounter;
            castPtr.m_refCounter->AddReference();
        }
       
        return castPtr;
    }
   
private:
    struct CountHolder : public CARefCount<TBase>
    {
        virtual ~CountHolder ()
        {
            TData * data = static_cast<TData 
*>(CARefCount<TBase>::m_pointee);
            delete data;
        }
    };
   
    // reference counter (owns the raw pointer):
    CARefCount<TBase> * m_refCounter;
}

template <typename TData, typename TBase>
CASharedPtr<TData, TBase> &
CASharedPtr<TData, TBase>::operator= (const CASharedPtr & fromSharedPtr)
{
    if (m_refCounter != fromSharedPtr.m_refCounter)
    {
        m_refCounter->RemoveReference ();
        m_refCounter = fromSharedPtr.m_refCounter;
        m_refCounter->AddReference ();
    }
   
    return (*this);
}




More information about the Qt-interest-old mailing list