/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2005 The OGRE Team 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. ----------------------------------------------------------------------------- */ #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) {} explicit SharedPtr(T* rep) : pRep(rep), pUseCount(new unsigned int(1)) { OGRE_NEW_AUTO_SHARED_MUTEX } SharedPtr(const SharedPtr& r) { // lock & copy other mutex pointer 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; release(); // lock & copy other mutex pointer OGRE_LOCK_MUTEX(*r.OGRE_AUTO_MUTEX_NAME) OGRE_COPY_AUTO_SHARED_MUTEX(r.OGRE_AUTO_MUTEX_NAME) pRep = r.pRep; pUseCount = r.pUseCount; if (pUseCount) { ++(*pUseCount); } 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 { assert(pUseCount); OGRE_LOCK_AUTO_SHARED_MUTEX return *pUseCount == 1; } inline unsigned int useCount() const { assert(pUseCount); OGRE_LOCK_AUTO_SHARED_MUTEX 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; OGRE_COPY_AUTO_SHARED_MUTEX(0) } } protected: inline void release(void) { bool destroyThis = false; { // 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(); } 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 } }; 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