diff --git a/include/osg/Referenced b/include/osg/Referenced index c006ea5bf..fb69c7db7 100644 --- a/include/osg/Referenced +++ b/include/osg/Referenced @@ -33,8 +33,9 @@ namespace osg { #ifndef OSG_JAVA_BUILD -// forward declar, declared after Referenced below. +// forward declare, declared after Referenced below. class DeleteHandler; +class Observer; /** Base class from providing referencing counted objects.*/ class OSG_EXPORT Referenced @@ -76,6 +77,11 @@ class OSG_EXPORT Referenced /** Return the number pointers currently referencing this object. */ inline int referenceCount() const { return _refCount; } + /** Add a Observer that is observering this object, notify the Observer when this object gets deleted.*/ + void addObserver(Observer* observer_ptr); + + /** Add a Observer that is observering this object, notify the Observer when this object gets deleted.*/ + void removeObserver(Observer* observer_ptr); public: @@ -98,9 +104,11 @@ class OSG_EXPORT Referenced protected: virtual ~Referenced(); - mutable OpenThreads::Mutex* _refMutex; + mutable OpenThreads::Mutex* _refMutex; - mutable int _refCount; + mutable int _refCount; + + void* _observers; }; diff --git a/include/osg/observer_ptr b/include/osg/observer_ptr new file mode 100644 index 000000000..c9b249e67 --- /dev/null +++ b/include/osg/observer_ptr @@ -0,0 +1,103 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library 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 + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSG_OBSERVER_PTR +#define OSG_OBSERVER_PTR + +namespace osg { + +class Observer +{ +public: + virtual ~Observer() {} + virtual void objectDeleted(void*) {} +}; + +/** Smart pointer for observed objects, that automatically set pointers to them to null when they deleted.*/ +template +class observer_ptr : public Observer +{ + + public: + typedef T element_type; + + observer_ptr() :_ptr(0L) {} + observer_ptr(T* t):_ptr(t) { if (_ptr) _ptr->addObserver(this); } + observer_ptr(const observer_ptr& rp):Observer(), _ptr(rp._ptr) { if (_ptr) _ptr->addObserver(this); } + ~observer_ptr() { if (_ptr) _ptr->removeObserver(this); _ptr=0; } + + inline observer_ptr& operator = (const observer_ptr& rp) + { + if (_ptr==rp._ptr) return *this; + if (_ptr) _ptr->removeObserver(this); + + _ptr = rp._ptr; + if (_ptr) _ptr->addObserver(this); + return *this; + } + + inline observer_ptr& operator = (T* ptr) + { + if (_ptr==ptr) return *this; + if (_ptr) _ptr->removeObserver(this); + + _ptr = ptr; + if (_ptr) _ptr->addObserver(this); + + return *this; + } + + virtual void objectDeleted(void* ptr) + { + if (_ptr==ptr) + { + _ptr = 0; + } + } + + // comparison operators for observer_ptr. + inline bool operator == (const observer_ptr& rp) const { return (_ptr==rp._ptr); } + inline bool operator != (const observer_ptr& rp) const { return (_ptr!=rp._ptr); } + inline bool operator < (const observer_ptr& rp) const { return (_ptr (const observer_ptr& rp) const { return (_ptr>rp._ptr); } + + // comparison operator for const T*. + inline bool operator == (const T* ptr) const { return (_ptr==ptr); } + inline bool operator != (const T* ptr) const { return (_ptr!=ptr); } + inline bool operator < (const T* ptr) const { return (_ptr (const T* ptr) const { return (_ptr>ptr); } + + + inline T& operator*() { return *_ptr; } + + inline const T& operator*() const { return *_ptr; } + + inline T* operator->() { return _ptr; } + + inline const T* operator->() const { return _ptr; } + + inline bool operator!() const { return _ptr==0L; } + + inline bool valid() const { return _ptr!=0L; } + + inline T* get() { return _ptr; } + + inline const T* get() const { return _ptr; } + + private: + T* _ptr; +}; + +} + +#endif diff --git a/src/osg/Referenced.cpp b/src/osg/Referenced.cpp index 4524f2a22..013599472 100644 --- a/src/osg/Referenced.cpp +++ b/src/osg/Referenced.cpp @@ -13,9 +13,11 @@ #include #include #include +#include #include #include +#include #include #include @@ -25,6 +27,8 @@ namespace osg { +typedef std::set ObserverSet; + static bool s_useThreadSafeReferenceCounting = getenv("OSG_THREAD_SAFE_REF_UNREF")!=0; static std::auto_ptr s_deleteHandler(0); static ApplicationUsageProxy Referenced_e0(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREAD_SAFE_REF_UNREF",""); @@ -50,18 +54,20 @@ DeleteHandler* Referenced::getDeleteHandler() return s_deleteHandler.get(); } -Referenced::Referenced() +Referenced::Referenced(): + _refMutex(0), + _refCount(0), + _observers(0) { if (s_useThreadSafeReferenceCounting) _refMutex = new OpenThreads::Mutex; - else _refMutex = 0; - _refCount=0; } -Referenced::Referenced(const Referenced&) +Referenced::Referenced(const Referenced&): + _refMutex(0), + _refCount(0), + _observers(0) { if (s_useThreadSafeReferenceCounting) _refMutex = new OpenThreads::Mutex; - else _refMutex = 0; - _refCount=0; } Referenced::~Referenced() @@ -72,6 +78,19 @@ Referenced::~Referenced() notify(WARN)<<" the final reference count was "<<_refCount<<", memory corruption possible."<(_observers); + for(ObserverSet::iterator itr = os->begin(); + itr != os->end(); + ++itr) + { + (*itr)->objectDeleted(this); + } + delete os; + _observers = 0; + } + if (_refMutex) { OpenThreads::Mutex* tmpMutexPtr = _refMutex; @@ -151,7 +170,36 @@ void Referenced::unref_nodelete() const --_refCount; } } - + +void Referenced::addObserver(Observer* observer_ptr) +{ + if (_refMutex) + { + OpenThreads::ScopedLock lock(*_refMutex); + + if (!_observers) _observers = new ObserverSet; + if (_observers) static_cast(_observers)->insert(observer_ptr); + } + else + { + if (!_observers) _observers = new ObserverSet; + if (_observers) static_cast(_observers)->insert(observer_ptr); + } +} + +void Referenced::removeObserver(Observer* observer_ptr) +{ + if (_refMutex) + { + OpenThreads::ScopedLock lock(*_refMutex); + + if (_observers) static_cast(_observers)->erase(observer_ptr); + } + else + { + if (_observers) static_cast(_observers)->erase(observer_ptr); + } +} }; // end of namespace osg