[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