// ========================================================================== // Template Specification : COXSPtr // ========================================================================== // Header file : OXSPtr.h // ////////////////////////////////////////////////////////////////////////// // Properties: // NO Abstract class (does not have any objects) // NO Derived from // NO Is a Cwnd. // NO Two stage creation (constructor & Create()) // NO Has a message map // NO Needs a resource (template) // NO Persistent objects (saveable on disk) // YES Uses exceptions // (CMemoryException by NULL-pointer dereference) // ////////////////////////////////////////////////////////////////////////// // Desciption : // This class works together with CObject derived classesto provide // a solution for smart pointers and objects // All access to the object must be done through its smart pointer // Normally construction of the object is done together with the // smart pointer. So when a smart pointer is constructed it also constructs // the object // When you specify NULL as parameter when construcing a smart pointer // it will not construct an object // The lifetime of objects is ruled by reference counting // When no references to the object exists it will be deleted. // You can remove the reference to an object explicitely by assigning // NULL to the smart pointer // You can also construct a new object explicitely by assigning the special value // NEW_OBJECT to it. // Apart from construction and destruction everything that can be done with a // normal (dumb) pointer can also be done with a smart pointer // Remark: // The runtime overhead of using a smart pointer instead of a dumb pointer // are very minimal // COXSPtr is a class with no base class and no virtual functions // The size of a smart pointer thus equals the size of its members : // two pointer (to the object and to the reference count). // All access functions of COXSPtr are inline and are very short. // E.g. operator-> just checks whether the pointer is not NULL // and returns it then // So computational overhead is minimal too. // When you try to dereference a smart pointer that is NULL // a CMemoryException will be thrown (and in DEBUG the function will ASSERT) // Prerequisites (necessary conditions): // ///////////////////////////////////////////////////////////////////////////// #ifndef __OXSPTR_H__ #define __OXSPTR_H__ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 #include "OXDllExt.h" // Defining ENABLE_SMART_WRAPPER enables the possibility to wrap a smart pointer // around an existing object. The locking functions are also available then. // By default this is not defined and thus not enabled // #define ENABLE_SMART_WRAPPER 1 // Defining DISABLE_SMART_DOWNCAST_TEST disnables the runtime test when a // smart pointer is downcasted (from base class to derived class) // By default this is not defined and thus enabled // #define DISABLE_SMART_DOWNCAST_TEST 1 // Defining DISABLE_SMART_SERIALIZATION disnables the serialization functionality // of a smart pointer (and groups) // By default this is not defined and thus enabled // #define DISABLE_SMART_SERIALIZATION 1 // Defining DISABLE_SMART_CHECK disables the runtime checks during Debug // These checks include wrapping a smart pointer around an existing object, // a smart pointer around a steck based object and cyclic graphs. // By default this is not defined and thus enabled // #define DISABLE_SMART_CHECK 1 // Use special creator object (NEW_OBJECT) that can be used in the // constructor and assignment operator of a smart pointer // to construct a new object class OX_CLASS_DECL COXObjectCreator { // This class is only used to mark a special parameter // during construction or assignment of a smart pointer // No actual members are needed }; extern OX_CLASS_DECL COXObjectCreator NEW_OBJECT; template class OX_CLASS_DECL COXSPtr; #ifndef DISABLE_SMART_SERIALIZATION template CArchive& AFXAPI operator<<(CArchive& ar, const COXSPtr& pSObj); template CArchive& AFXAPI operator>>(CArchive& ar, COXSPtr& pSObj); #endif // DISABLE_SMART_SERIALIZATION template class OX_CLASS_DECL COXSPtr { // Data members ------------------------------------------------------------- public: protected: T* m_pSmartObject; LONG* m_pnReferenceCount; private: // Member functions --------------------------------------------------------- public: COXSPtr(const COXObjectCreator& objCreator = NEW_OBJECT); // --- In : objCreator : NEW_OBJECT : Creates a new object // --- Out : // --- Returns : // --- Effect : This constructs a smart pointer and it also // creates the associated object // This is the default constructor // The only valid parameter is NEW_OBJECT #ifndef ENABLE_SMART_WRAPPER COXSPtr(const COXObjectCreator* pNull); // --- In : pNull : NULL // --- Out : // --- Returns : // --- Effect : This constructs a smart NULL pointer // The only valid parameter is NULL #else COXSPtr(T* pSObj); // --- In : pSObj : Pointer to the object // around which this smart pointer will be created // or NULL : Makes this a NULL-pointer // --- Out : // --- Returns : // --- Effect : This constructs a smart pointer around an existing // object or constructs a smart NULL pointer // The object's lifetime is now decided by the smart pointer // You should not delete the object directly #endif // ENABLE_SMART_WRAPPER COXSPtr(const COXSPtr& sPtr); // --- In : sPtr : The smart pointer to be copied // --- Out : // --- Returns : // --- Effect : Copy constructor COXSPtr& operator=(const COXSPtr& sPtr); // --- In : sPtr : A smart pointer // --- Out : // --- Returns : // --- Effect : Assignment operator COXSPtr& operator=(const COXObjectCreator& objCreator); // --- In : objCreator : NEW_OBJECT // --- Out : // --- Returns : // --- Effect : Constructs a new object and assigns it to this smart pointer // The only valid parameter is NEW_OBJECT #ifndef ENABLE_SMART_WRAPPER COXSPtr& operator=(const COXObjectCreator* pNull); // --- In : pNull : NULL // --- Out : // --- Returns : // --- Effect : Makes this smart pointer a smart NULL pointer // The only valid parameter is NULL #else COXSPtr& operator=(T* pSObj); // --- In : pSObj : A pointer to the object or NULL // --- Out : // --- Returns : // --- Effect : Assignment operator // If pSObj == NULL this smart pointer becomes a smart NULL pointer // The object's lifetime is now decided by the smart pointer // You should not delete the object directly #endif // ENABLE_SMART_WRAPPER T& operator*() const; // throw(CMemoryException); // --- In : // --- Out : // --- Returns : The object pointed to // --- Effect : Dereference operator T* operator->() const; // throw(CMemoryException); // --- In : // --- Out : // --- Returns : Pointer to the object // --- Effect : Member operator operator T*() const; // --- In : // --- Out : // --- Returns : // --- Effect : Conversion operator BOOL operator!() const; // --- In : // --- Out : // --- Returns : Whether this pointer points to NULL (TRUE) or to // a valid object (FALSE) // --- Effect : BOOL operator==(T* pSObj) const; // --- In : pSObj : Pointer to a smart element // --- Out : // --- Returns : Whether this pointer points to the specified // object // --- Effect : BOOL operator!=(T* pSObj) const; // --- In : pSObj : Pointer to a smart element // --- Out : // --- Returns : Whether this pointer does not point to the specified // object // --- Effect : #ifndef DISABLE_SMART_SERIALIZATION friend CArchive& AFXAPI operator<<(CArchive& ar, const COXSPtr& pSObj); // --- In : ar : Archive to store the object in // pSObj : Object to store // --- Out : // --- Returns : The archive itself // --- Effect : This functions serializes the object wrapped by this smart pointer // Object I/O is pointer based to avoid added construction overhead and // to support polymorphism // Use the Serialize member function directly for embedded objects. friend CArchive& AFXAPI operator>>(CArchive& ar, COXSPtr& pSObj); // --- In : ar : Archive to load the object from // pSObj : Object pointer to load into // --- Out : // --- Returns : The archive itself // --- Effect : This functions serializes the object into this smart pointer // Object I/O is pointer based to avoid added construction overhead and // to support polymorphism // Use the Serialize member function directly for embedded objects. #endif // DISABLE_SMART_SERIALIZATION COXSPtr& PolyAssign(T* pSObj, LONG* pnReferenceCount); // --- In : pSObj : Pointer to a T or T derived object // pnReferenceCount : Pointer to its reference count // --- Out : // --- Returns : A smart pointer wrapping the object // --- Effect : Assignment function, internally used for // polymorphic assignment // Do not call this function directly, use // the operator <<= instead LONG* GetRefCountAddress() const; // --- In : // --- Out : // --- Returns : The address of the reference count of the object // or NULL when smart null pointer // --- Effect : Helper function, internally used for polymorphic assignment // Do not call this function directly, use // the operator <<= instead #ifdef ENABLE_SMART_WRAPPER // CAUTION : THE NEXT THREE FUNCTIONS ARE NOT INTENDED FOR NORMAL USE // THEY DISABLE A LOT OF IMPORTANT FUNCTIONALITY AND // SHOULD ONLY BE USED IN EXCEPTIONAL CIRCUMSTANCES void Lock(); // --- In : // --- Out : // --- Returns : // --- Effect : Locks all the smart pointers that point to the object // this smart pointer points to // Locking will disable automatic deletion when the // reference count reaches 0 void Unlock(); // --- In : // --- Out : // --- Returns : // --- Effect : Unlocks all the smart pointers that point to the object // this smart pointer points to // Unlocking will re-enable automatic deletion when the // reference count reaches 0 BOOL IsLocked(); // --- In : // --- Out : // --- Returns : Whether the smart pointer is locked or not // --- Effect : #endif // ENABLE_SMART_WRAPPER #ifdef _DEBUG void AssertValid() const; #endif // _DEBUG ~COXSPtr(); // --- In : // --- Out : // --- Returns : // --- Effect : This destructs the pointer object protected: LONG Grab(); LONG Release(); private: }; template inline COXSPtr& SmartUpCast(COXSPtr& pBaseObj, const COXSPtr& pObj) // --- In : pBaseObj : Smart pointer you want to assign to // pObj : Smart pointer being assigned // --- Out : // --- Returns : The smart pointer assigned to // --- Effect : This is the 'polymorphic assignemnt' operator // A smart pointer wrapping a T object can be assigned to a // smart pointer normally wrapping BASE_T object, // if T* could be assigned to BASE_T* // This means T must be derived from BASE_T { // The next line will generate a compiler error (cannot convert parameter 1 from ...) // if T (pObj) is not derived from BASE_T (pBaseObj) return pBaseObj.PolyAssign(pObj, pObj.GetRefCountAddress()); }; template inline COXSPtr& operator<<=(COXSPtr& pBaseObj, const COXSPtr& pObj) { return SmartUpCast(pBaseObj, pObj); }; template inline COXSPtr& SmartDownCast(COXSPtr& pObj, const COXSPtr& pBaseObj) // --- In : pObj : Smart pointer you want to assign to // pBaseObj : Smart pointer being assigned // --- Out : // --- Returns : The smart pointer assigned to // --- Effect : This is the 'cast assignemnt' operator // A smart pointer wrapping a BASE_T object will be assigned to a // smart pointer wrapping a T object, // A runtime check will be performed, to check the validity // When an incorrect cast is performed a smart NULL pointer is returned { #ifndef DISABLE_SMART_DOWNCAST_TEST // The macro DYNAMIC_DOWNCAST does not work with templates, so we mimic that functionality // ... Build a (temporary T object) just to get to the runtime class COXSPtr pDummyObj; if (pBaseObj != NULL && !pBaseObj->IsKindOf(pDummyObj->GetRuntimeClass())) { TRACE(_T("SmartDownCast (Cast assignment) returning smart NULL pointer\n")); return pObj.PolyAssign(NULL, NULL); } else #endif // DISABLE_SMART_DOWNCAST_TEST return pObj.PolyAssign((T*)(BASE_T*)pBaseObj, pBaseObj.GetRefCountAddress()); }; template inline COXSPtr& operator>>=(COXSPtr& pObj, const COXSPtr& pBaseObj) { return SmartDownCast(pObj, pBaseObj); }; #include "OXSPtr.inl" #endif // __OXSPTR_H__ // ==========================================================================