#ifndef SMARTPOINTERS_H #define SMARTPOINTERS_H ///////////////////////////////////////////////////////////////////////// // SmartPointers.h - Manage objects on heap, using Reference Counting // // ver 1.2 // // Language: Visual C++, ver 8.0 // // Platform: Dell Dimension 9150, Windows XP, SP2 // // Application: CSE687 - Object Oriented Design, Prototype // // Author: Jim Fawcett, Syracuse University, CST 2-187 // // (315) 443-3948, jfawcett@twcny.rr.com // ///////////////////////////////////////////////////////////////////////// /* Module Operations: ================== This module provides three classes: smartPtr - manages objects on the C++ heap by reference counting refCounted - wrapper that adds reference counting to uncounted types wrapped - class wrapper for primitive types, enables refCounted wrapping for non-class types The smartPtr class is particularly useful for storing smart pointers to polymorphic objects in STL containers. Using these facilities allows you to avoid managing the containers object deallocation yourself. Public Interface: ================= typedef wrapped wDouble; typedef refCounted< wDouble > CountedDouble; smartPtr< CountedDouble > spDouble1(new CountedDouble(3.1415927)); class Base { ... }; typedef refCount CountedBase; class CountedDerived : public CountedBase { ... }; smartPtr spBase2(new CountedDerived); spBase2->announce(); */ /* Build Process: ============== Required Files SmartPointers.h, SmartPointers.cpp Compiler Command cl /EHsc /DTEST_SMARTPOINTERS SmartPointers.cpp Maintenance History: ==================== ver 1.2 : 01 Mar 06 - cosmetic changes to layout and comments ver 1.1 : 23 Feb 06 - fixed bug identified by Don McGarry. The non-templatized class irefCount incorrectly defined a member function, announce, in its header file. I've moved that to the implementation file of this module. Now, you must include the smartPointers.cpp in your project to use the irefCounted class. ver 1.0 : 18 Feb 06 - first release */ // /////////////////////////////////////////////////// // smartPtr class /////////////////////////////////////////////////// template class smartPtr { public: ///////////////////////////////////////// // template member template smartPtr(U* pU); smartPtr(); smartPtr(const smartPtr& sp); virtual ~smartPtr(); smartPtr& operator=(const smartPtr& sp); T& operator*(); T* operator->(); protected: T* m_pTr; }; //----< constructor taking pointer to heap >------------------------- // // This constructor expects you to use syntax like this: // smartPtr pBaseWidget(new Widget); // That is, pU must point to the C++ heap. // template template inline smartPtr::smartPtr(U* pU) : m_pTr(pU) { m_pTr->addRef(); } //----< constructor creates null pointer >--------------------------- template inline smartPtr::smartPtr() : m_pTr(0) {} //----< copy constructor >------------------------------------------- template smartPtr::smartPtr(const smartPtr& sp) : m_pTr(sp.m_pTr) { if(m_pTr) m_pTr->addRef(); } //----< destructor >------------------------------------------------- template smartPtr::~smartPtr() { if(m_pTr) m_pTr->release(); } // //----< dereference operator >--------------------------------------- template inline T& smartPtr::operator*() { return *m_pTr; } //----< selection operator >----------------------------------------- template inline T* smartPtr::operator->() { return m_pTr; } //----< assignment operator >---------------------------------------- template smartPtr& smartPtr::operator=(const smartPtr& sp) { if(this == &sp) return *this; if(m_pTr) m_pTr->release(); m_pTr = sp.m_pTr; m_pTr->addRef(); return *this; } // ///////////////////////////////////////////////////////////////////// // irefCount class: // - Base class for an object that needs to be managed by a // smartPtr with reference counting machinery. ///////////////////////////////////////////////////////////////////// class irefCounted { public: irefCounted() : m_refCount(0) { myWrapperCount = ++wrapperCount; } irefCounted(const irefCounted& rc) : m_refCount(0) { myWrapperCount = ++wrapperCount; } virtual ~irefCounted() { announce(destroying); } void addRef() { ++m_refCount; } void release() { if(--m_refCount == 0) { announce(releasing); delete this; } } enum annType { creating, releasing, destroying }; virtual void announce(annType at=creating); protected: unsigned m_refCount; static unsigned wrapperCount; unsigned myWrapperCount; }; // ///////////////////////////////////////////////////////////////////// // refCount class: // - Wraps an object that needs it to be managed by a smartPtr with // reference counting machinery. // - the wrapperCount and myWrapperCount are just for tutorial purposes, // so you can see what objects are created and destroyed. They can be // removed, without harm, to make the class smaller and more readable. ///////////////////////////////////////////////////////////////////// template class refCounted : public T { friend class smartPtr< refCounted >; public: refCounted() : m_refCount(0) { myWrapperCount = ++wrapperCount; } refCounted(const T& t) : m_refCount(0), T(t) { myWrapperCount = ++wrapperCount; } refCounted(const refCounted& rc) : m_refCount(0) { myWrapperCount = ++wrapperCount; } virtual ~refCounted() { announce(destroying); } refCounted& operator=(const refCounted& rc) { if(this == &rc) return *this; static_cast(*this) = rc; // assign base part return *this; } refCounted& operator=(const T& t) { static_cast(*this) = t; // assign to base part return *this; } enum annType { creating, releasing, destroying }; virtual void announce(annType at=creating); protected: void addRef() { ++m_refCount; } void release() { if(--m_refCount == 0) { announce(releasing); delete this; } } unsigned m_refCount; static unsigned wrapperCount; unsigned myWrapperCount; }; template unsigned refCounted::wrapperCount = 0; // #ifdef VERBOSE #include #endif template void refCounted::announce(annType at) { #ifdef VERBOSE if(at==creating) std::cout << "\n create "; else if(at==releasing) std::cout << "\n release - "; else std::cout << "\n destroy - "; std::cout << "ref counted obj #" << myWrapperCount; std::cout << ", of type " << typeid(*this).name(); std::cout.flush(); #endif } /////////////////////////////////////////////////// // wrapper for non-class types /////////////////////////////////////////////////// // - intended to wrap C++ primitives for sharing // - makes a class that behaves like a primitive // but can be inherited by the refCount class /////////////////////////////////////////////////// template class wrapped // can't inherit from T { public: wrapped() : m_T(0) {} wrapped(const wrapped& w) : m_T(w.m_T) {} wrapped(T t) : m_T(t) {} wrapped& operator=(T t) { m_T = t; } operator T () { return m_T; } virtual ~wrapped() {} private: T m_T; }; #endif