X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fstructure%2FSGWeakReferenced.hxx;h=3bb70ffa6e541178db502667f7de71bc4ab99097;hb=5c9f5361bda56dddad8068d8e45dc08584440d70;hp=8108300e7b1fa562d5b2264b7217f37a9019d809;hpb=0f7b65a9216458b290113bae0ff75bd3ec4dce36;p=simgear.git diff --git a/simgear/structure/SGWeakReferenced.hxx b/simgear/structure/SGWeakReferenced.hxx index 8108300e..3bb70ffa 100644 --- a/simgear/structure/SGWeakReferenced.hxx +++ b/simgear/structure/SGWeakReferenced.hxx @@ -21,9 +21,30 @@ #include "SGReferenced.hxx" #include "SGSharedPtr.hxx" +#include +#include + +#ifdef _MSC_VER +# pragma warning(push) + // C4355: 'this' : used in base member initializer list + // Tell MSVC we know what we do and really want to do it this way. +# pragma warning(disable: 4355) +#endif + template class SGWeakPtr; +class SGVirtualWeakReferenced; +/** + * Base class for all reference counted SimGear objects supporting weak + * references, not incrementing the reference count. + * + * Classes derived from this one are meant to be managed with the SGSharedPtr + * and SGWeakPtr classes. + * + * If the class hierarchy contains virtual base classes use + * SGVirtualWeakReferenced instead. + */ class SGWeakReferenced { public: /// The object backref and the reference count for this object need to be @@ -50,11 +71,11 @@ public: /// The usual operations on weak pointers. /// The interface should stay the same then what we have in Referenced. static unsigned get(const SGWeakReferenced* ref) - { if (ref) return ++(ref->mWeakData->mRefcount); else return 0u; } + { if (ref) return ++(ref->mWeakData->mRefcount); else return 0; } static unsigned put(const SGWeakReferenced* ref) - { if (ref) return --(ref->mWeakData->mRefcount); else return ~0u; } + { if (ref) return --(ref->mWeakData->mRefcount); else return 0; } static unsigned count(const SGWeakReferenced* ref) - { if (ref) return ref->mWeakData->mRefcount; else return 0u; } + { if (ref) return ref->mWeakData->mRefcount; else return 0; } private: /// Support for weak references, not increasing the reference count @@ -82,7 +103,7 @@ private: } while (!mRefcount.compareAndExchange(count, count + 1)); // We know that as long as the refcount is not zero, the pointer still // points to valid data. So it is safe to work on it. - return static_cast(mWeakReferenced); + return up_cast(mWeakReferenced); } SGAtomic mRefcount; @@ -92,6 +113,27 @@ private: WeakData(void); WeakData(const WeakData&); WeakData& operator=(const WeakData&); + + /// Upcast in a class hierarchy with a virtual base class + template + static + typename boost::enable_if< + boost::is_base_of, + T* + >::type + up_cast(SGWeakReferenced* ptr); + + /// Upcast in a non-virtual class hierarchy + template + static + typename boost::disable_if< + boost::is_base_of, + T* + >::type + up_cast(SGWeakReferenced* ptr) + { + return static_cast(ptr); + } }; SGSharedPtr mWeakData; @@ -100,4 +142,58 @@ private: friend class SGWeakPtr; }; +/** + * Base class for all reference counted SimGear objects with virtual base + * classes, supporting weak references. + * + * Classes derived from this one are meant to be managed with the SGSharedPtr + * and SGWeakPtr classes. + * + * @code{cpp} + * + * class Base1: + * public virtual SGVirtualWeakReferenced + * {}; + * + * class Base2: + * public virtual SGVirtualWeakReferenced + * {}; + * + * class Derived: + * public Base1, + * public Base2 + * {}; + * + * SGSharedPtr ptr( new Derived() ); + * SGWeakPtr weak_ptr( ptr ); + * SGSharedPtr ptr1( weak_ptr.lock() ); + * SGSharedPtr ptr2( weak_ptr.lock() ); + * + * @endcode + */ +class SGVirtualWeakReferenced: + public SGWeakReferenced +{ + public: + virtual ~SGVirtualWeakReferenced() {} +}; + +/// Upcast in a class hierarchy with a virtual base class +// We (clang) need the definition of SGVirtualWeakReferenced for the static_cast +template +typename boost::enable_if< + boost::is_base_of, + T* +>::type +SGWeakReferenced::WeakData::up_cast(SGWeakReferenced* ptr) +{ + // First get the virtual base class, which then can be used to further + // upcast. + return dynamic_cast(static_cast(ptr)); +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + #endif