#ifndef Hebe_Cpp_Ref_H /* -*- c++ -*- */ #define Hebe_Cpp_Ref_H #define EXTRA_DEBUG 0 #if EXTRA_DEBUG #include #endif #include /** * This exception is thrown when an attempt is made to call * ref<>.downcast<>() on something that is not an instance of the type * cast to. */ class InvalidDowncastException: public std::exception { public: InvalidDowncastException() {} virtual char const *what() const throw() { return "Invalid Downcast Exception (ref.h)"; } }; template class ref; /** * Base class for all objects that may have their store managed by * class ref<>. */ class Referenceable { private: template friend class ref; int count; ///< number of references to this object public: Referenceable() : count(0) {} virtual ~Referenceable() {} }; template class ref { private: template friend class ref; Referenceable *rep; /** * Make this reference refer to the parameter passed in. * * @param obj the new referee */ void become(T *obj) { rep = obj; if (valid()) { #if EXTRA_DEBUG fprintf(stderr, "this %p rep %p incr count %d -> %d\n", this, rep, rep->count, rep->count+1); #endif rep->count++; } } public: /** * Construct a reference to an object of the value-type of this * instantiation of the ref<> template. */ ref(T *obj) { become(obj); } /** * Construct a nil reference. */ ref() { rep = 0; } /** * Copy constructor - refer to the same object as the reference * passed in. */ ref(ref const &from) { become((T *) from.rep); } /** * Copy constructor for making base-references refer to * derived-objects via a derived-reference. */ template ref(ref const &from) { become((DerivedT *) from.rep); } /** * Destructor - decrements reference count by calling release(). */ ~ref() { release(); } /** * Assignment operator - makes this reference refer to the referee * of the passed-in reference. */ ref const &operator =(ref const &from) { if (this != &from) { release(); become((T *) from.rep); } else { } return (*this); } /** * Decrement reference count, and if it reaches zero, delete our * referee. The only real use for this is when you have made a * reference refer to a referee previously extracted using * extract(), and you now wish to correct the resulting * reference-count imbalance. */ void unref() { if (rep != 0) { #if EXTRA_DEBUG fprintf(stderr, "this %p rep %p decr count %d -> %d\n", this, rep, rep->count, rep->count-1); #endif (rep->count)--; if (rep->count <= 0) { #if EXTRA_DEBUG fprintf(stderr, "this %p rep %p DELETING REP\n", this, rep); #endif delete rep; } } else { } } /** * Call unref() to release our referee, and then clear our rep * pointer. */ void release() { unref(); rep = 0; } /** * Check a reference to see if it is nil or not. * * @return true if this is a non-nil reference; false if this * reference is nil. */ bool valid() const { return rep != 0; } /** * Extract the number of active references that exist against the * referee of this reference. * * @return the referee's active reference count. */ int stat() const { return (rep ? rep->count : 0); } /** * Explicit dereference operator - chain the dereference through to * our referee. Note that this requires this reference to be * non-nil - see valid(). * * @return an object of our value-type: our current referee. */ T &operator *() const { #if EXTRA_DEBUG assert(rep); #endif return * (T *) rep; } /** * Implicit dereference operator - convert this reference to an * object of type pointer-to-value-type. Note that while this does * not technically require this reference to be valid(), the * resulting pointer will be instantly dereferenced anyway, which * for a non-valid() reference will cause SIGSEGV. * * @return a pointer to our referee */ T *operator ->() const { #if EXTRA_DEBUG assert(rep); #endif return (T *) rep; } /** * Allows direct access to our referee. * * @return a pointer to our referee */ T *get() const { return (T *) rep; } /** * Cast operator - allows for casting this reference directly to * type pointer-to-value-type. * * @return a pointer to our referee */ operator T *() const { #if EXTRA_DEBUG assert(rep); #endif return (T *) rep; } /** * Extraction of the referee - this returns our referee, and * makes this reference a nil reference, without modifying the * reference-count of the referee. This function can cause * memory leaks if used without due care and attention - be careful! * * @return a pointer to our referee */ T *extract() { #if EXTRA_DEBUG assert(rep); #endif T *result = (T *) rep; rep = 0; return result; } /** * Downcast operation - convert a reference-to-base-type into a * reference-to-derived-type, if the current referee supports such a * downcast itself (ie. if it is an instance of the derived type). * * @return a reference of value type "derived", referring to our referee * @exception InvalidDowncastException if referee is not of type "derived" */ template ref downcast() const { #if EXTRA_DEBUG assert(rep); #endif if (dynamic_cast((T *) rep) == 0) throw InvalidDowncastException(); return ref((DerivedT *) rep); } }; #endif