/****************************************************************************** * * $Id: $ * * Copyright (C) 1997-2012 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * * Documents produced by Doxygen are derivative works derived from the * input used in their production; they are not affected by this license. * */ #ifndef LOCKINGPTR_H #define LOCKINGPTR_H /*! @brief Abstract interface for lockable objects. * * By implementing this interface, a smart pointer can be created which * will lock this object. This is used to prevent that an internal pointer * owned by a lockable object would become invalid when the object is removed from * memory, leaving the client with an invalid pointer. By letting the client use * a smart pointer instead of the real object the object will be locked into * memory until the pointer is no longer used, at which point the owner object will be * unlock and can be removed from memory. */ class LockableObj { public: LockableObj() : m_lockCount(0) {} virtual ~LockableObj() {} /*! Returns TRUE if the object is currently locked. */ bool isLocked() const { return m_lockCount>0; } //VC++6.0 workaround // protected: /*! Called when the object is locked. */ virtual void lock() const = 0; /*! Called when the object is unlocked. */ virtual void unlock() const = 0; //VC++6.0 workaround // private: // template friend class LockingPtr; int m_lockCount; }; /*! @brief Smart pointer which keeps a lock on the owner of the pointer. * * With the pointer an owner object derived from LockableObj is associated. * As long as the smart object exists it will keep a lock on the obj by calling * LockableObj::lock(). Smart pointers can be copied and passed by value. As * soon as there or no more smart pointer references to the object, * LockableObj::unlock() will be called automatically. */ template class LockingPtr { LockableObj *m_owner; const T *m_ptr; public: /*! Creates a smart pointer for pointer \a p owned by object \a o. */ LockingPtr(const LockableObj *o,const T* p) { if (o->m_lockCount==0) o->lock(); m_owner = (LockableObj *)o; m_owner->m_lockCount++; m_ptr = p; } /*! Copies the smart pointer \a lp */ LockingPtr(const LockingPtr &lp) { m_ptr = lp.m_ptr; m_owner = lp.m_owner; m_owner->m_lockCount++; } /*! Assigns the smart pointer \a lp */ LockingPtr &operator=(const LockingPtr &lp) { m_owner->m_lockCount--; if (m_owner->m_lockCount==0) // no more references { m_owner->unlock(); } m_ptr = lp.m_ptr; m_owner = lp.m_owner; m_owner->m_lockCount++; return *this; } /*! Destroys the smart pointer, will unlock the owner. */ ~LockingPtr() { m_owner->m_lockCount--; if (m_owner->m_lockCount==0) // no more references { m_owner->unlock(); } } bool isNull() const { return m_ptr==0; } bool operator!() const { return !m_ptr; } bool operator==(T *p) const { return m_ptr==p; } bool operator==(const LockingPtr &lp) const { return m_ptr==lp.m_ptr; } bool operator!=(T *p) const { return m_ptr!=p; } bool operator!=(const LockingPtr &lp) const { return m_ptr!=lp.m_ptr; } /*! Dereference operator */ const T& operator* () const { return *m_ptr; } T* pointer() const { return (T*)m_ptr; } /*! Pointer operator */ T* operator-> () const { return (T*)m_ptr; } }; #endif // LOCKINGPTR_H