#include #include // ******************************************************************* // REFERENCE COUNTING ENVELOPE AROUND POINTER TO (GENERIC) Type // ******************************************************************* template class RefCount { public: RefCount(Type * ptr) : myCount(1), myPtr(ptr) {} // =================================================== // MAY NEED TO SPECIALIZE THIS FOR SOME Types // (EG: MOST POINTER TYPES, SEE BELOW) // =================================================== RefCount * Clone(void); // ========================= // HANDLE REFERENCE COUNTING // ========================= RefCount* Incr(void) const { myCount++; return const_cast(this); } void Decr(void) { if (--myCount==0) { delete this; } } Type* Ptr(void) { return myPtr; } private: ~RefCount(void) { delete myPtr; } mutable int myCount; Type* myPtr; }; template RefCount* RefCount::Clone(void) { return new RefCount (new Type (*myPtr)); } // ******************************************************************* // SPECIALIZATION OF RefCount::Clone FOR chars, // (SINCE char* ALMOST ALWAYS POINTS TO A NULL-TERMINATED STRING) // ******************************************************************* // THE DRAFT STANDARD STATES THAT A COMPLETE SPECIALIZATION STILL NEEDS // A template KEYWORD, LIKE THIS (BUT g++ 2.7.2 DOESN'T UNDERSTAND IT): // // template <> RefCount* RefCount::Clone(void) { return new RefCount (myPtr?strdup(myPtr):0); } // ******************************************************************* // EXAMPLE OF USE OF REFERENCE COUNTING // ******************************************************************* template class RefCountedPtrTo { public: RefCountedPtrTo(void) : myRefCount(new RefCount(0)) {} RefCountedPtrTo(Type* ptr) : myRefCount(new RefCount(ptr)) {} // ========================= // NOTE COPY CTOR IS SPECIAL // ========================= RefCountedPtrTo(const RefCountedPtrTo & p) : myRefCount(p.myRefCount->Incr()) {} ~RefCountedPtrTo(void) { myRefCount->Decr(); } // ================== // NORMAL POINTER OPS // ================== class Proxy { public: Proxy(RefCount*& refCount, int index) : myRefCount(refCount), myIndex(index) {} operator const Type& (void) { return (myRefCount->Ptr())[myIndex]; } Proxy& operator=(const Type& t) { RefCount* oldRefCount = myRefCount; myRefCount = oldRefCount->Clone(); oldRefCount->Decr(); (myRefCount->Ptr())[myIndex] = t; return *this; } private: RefCount*& myRefCount; int myIndex; }; Proxy operator[] (int index) { return Proxy(myRefCount,index); } Proxy operator* (void) { return Proxy(myRefCount,0); } operator Type* (void) { return myRefCount->Ptr(); } operator const Type* (void) { return myRefCount->Ptr(); } RefCountedPtrTo& operator= (const RefCountedPtrTo& p) { if (myRefCount != p.myRefCount) { myRefCount->Decr(); myRefCount = p.myRefCount->Incr(); } return *this; } void Detach(void) { RefCount* oldRefCount = myRefCount; myRefCount = oldRefCount->Clone(); oldRefCount->Decr(); } private: RefCount* myRefCount; }; #define SHOW(WHATEVER) \ cout << "\"" << __FILE__ << "\", line " << __LINE__ \ << ": " #WHATEVER " = " << WHATEVER << endl; int main(void) { RefCountedPtrTo ptr0; RefCountedPtrTo ptr1; RefCountedPtrTo ptr2 = "ptr2"; ptr0 = ptr1 = ptr2; SHOW(ptr0); // "ptr2" SHOW(ptr1); // "ptr2" SHOW(ptr2); // "ptr2" ptr2[3] = '3'; SHOW(ptr0); // "ptr3" SHOW(ptr1); // "ptr3" SHOW(ptr2); // "ptr3" ptr2.Detach(); ptr2[3] = '4'; SHOW(ptr0); // "ptr3" SHOW(ptr1); // "ptr3" SHOW(ptr2); // "ptr4" ptr1[3] = '5'; SHOW(ptr0); // "ptr5" SHOW(ptr1); // "ptr5" SHOW(ptr2); // "ptr4" ptr2.Detach(); SHOW(ptr0); // "ptr5" SHOW(ptr1); // "ptr5" SHOW(ptr2); // "ptr4" return 0; }