/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2006 Torus Knot Software Ltd Also see acknowledgements in Readme.html This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt. You may alternatively use this source under the terms of a specific version of the OGRE Unrestricted License provided you have obtained such a license from Torus Knot Software Ltd. ----------------------------------------------------------------------------- */ #ifndef __SharedPtr_H__ #define __SharedPtr_H__ #include "OgrePrerequisites.h" namespace Ogre { /** Reference-counted shared pointer, used for objects where implicit destruction is required. @remarks This is a standard shared pointer implementation which uses a reference count to work out when to delete the object. OGRE does not use this class very often, because it is usually more efficient to make the destruction of objects more intentional (in blocks, say). However in some cases you really cannot tell how many people are using an object, and this approach is worthwhile (e.g. ControllerValue) @par If OGRE_THREAD_SUPPORT is defined to be 1, use of this class is thread-safe. */ template class SharedPtr { protected: T* pRep; unsigned int* pUseCount; public: OGRE_AUTO_SHARED_MUTEX // public to allow external locking /** Constructor, does not initialise the SharedPtr. @remarks Dangerous! You have to call bind() before using the SharedPtr. */ SharedPtr() : pRep(0), pUseCount(0) { OGRE_SET_AUTO_SHARED_MUTEX_NULL } template< class Y> explicit SharedPtr(Y* rep) : pRep(rep), pUseCount(new unsigned int(1)) { OGRE_SET_AUTO_SHARED_MUTEX_NULL OGRE_NEW_AUTO_SHARED_MUTEX } SharedPtr(const SharedPtr& r) : pRep(0), pUseCount(0) { // lock & copy other mutex pointer OGRE_SET_AUTO_SHARED_MUTEX_NULL OGRE_MUTEX_CONDITIONAL(r.OGRE_AUTO_MUTEX_NAME) { OGRE_LOCK_MUTEX(*r.OGRE_AUTO_MUTEX_NAME) OGRE_COPY_AUTO_SHARED_MUTEX(r.OGRE_AUTO_MUTEX_NAME) pRep = r.pRep; pUseCount = r.pUseCount; // Handle zero pointer gracefully to manage STL containers if(pUseCount) { ++(*pUseCount); } } } SharedPtr& operator=(const SharedPtr& r) { if (pRep == r.pRep) return *this; // Swap current data into a local copy // this ensures we deal with rhs and this being dependent SharedPtr tmp(r); swap(tmp); return *this; } template< class Y> SharedPtr(const SharedPtr& r) : pRep(0), pUseCount(0) { // lock & copy other mutex pointer OGRE_SET_AUTO_SHARED_MUTEX_NULL OGRE_MUTEX_CONDITIONAL(r.OGRE_AUTO_MUTEX_NAME) { OGRE_LOCK_MUTEX(*r.OGRE_AUTO_MUTEX_NAME) OGRE_COPY_AUTO_SHARED_MUTEX(r.OGRE_AUTO_MUTEX_NAME) pRep = r.getPointer(); pUseCount = r.useCountPointer(); // Handle zero pointer gracefully to manage STL containers if(pUseCount) { ++(*pUseCount); } } } template< class Y> SharedPtr& operator=(const SharedPtr& r) { if (pRep == r.pRep) return *this; // Swap current data into a local copy // this ensures we deal with rhs and this being dependent SharedPtr tmp(r); swap(tmp); return *this; } virtual ~SharedPtr() { release(); } inline T& operator*() const { assert(pRep); return *pRep; } inline T* operator->() const { assert(pRep); return pRep; } inline T* get() const { return pRep; } /** Binds rep to the SharedPtr. @remarks Assumes that the SharedPtr is uninitialised! */ void bind(T* rep) { assert(!pRep && !pUseCount); OGRE_NEW_AUTO_SHARED_MUTEX OGRE_LOCK_AUTO_SHARED_MUTEX pUseCount = new unsigned int(1); pRep = rep; } inline bool unique() const { OGRE_LOCK_AUTO_SHARED_MUTEX assert(pUseCount); return *pUseCount == 1; } inline unsigned int useCount() const { OGRE_LOCK_AUTO_SHARED_MUTEX assert(pUseCount); return *pUseCount; } inline unsigned int* useCountPointer() const { return pUseCount; } inline T* getPointer() const { return pRep; } inline bool isNull(void) const { return pRep == 0; } inline void setNull(void) { if (pRep) { // can't scope lock mutex before release incase deleted release(); pRep = 0; pUseCount = 0; } } protected: inline void release(void) { bool destroyThis = false; /* If the mutex is not initialized to a non-zero value, then neither is pUseCount nor pRep. */ OGRE_MUTEX_CONDITIONAL(OGRE_AUTO_MUTEX_NAME) { // lock own mutex in limited scope (must unlock before destroy) OGRE_LOCK_AUTO_SHARED_MUTEX if (pUseCount) { if (--(*pUseCount) == 0) { destroyThis = true; } } } if (destroyThis) destroy(); OGRE_SET_AUTO_SHARED_MUTEX_NULL } virtual void destroy(void) { // IF YOU GET A CRASH HERE, YOU FORGOT TO FREE UP POINTERS // BEFORE SHUTTING OGRE DOWN // Use setNull() before shutdown or make sure your pointer goes // out of scope before OGRE shuts down to avoid this. delete pRep; delete pUseCount; OGRE_DELETE_AUTO_SHARED_MUTEX } virtual void swap(SharedPtr &other) { std::swap(pRep, other.pRep); std::swap(pUseCount, other.pUseCount); #if OGRE_THREAD_SUPPORT std::swap(OGRE_AUTO_MUTEX_NAME, other.OGRE_AUTO_MUTEX_NAME); #endif } }; template inline bool operator==(SharedPtr const& a, SharedPtr const& b) { return a.get() == b.get(); } template inline bool operator!=(SharedPtr const& a, SharedPtr const& b) { return a.get() != b.get(); } } #endif