Chapter 2 of the art of c++ #ifndef GC_H_ #define GC_H_ #include <iostream> #include <list> #include <typeinfo> #include <cstdlib> using namespace std; #define DISPLAY class OutOfRangeExc { //Add functionality if needed by your application. }; template <class T> class Iter { T *ptr;//current pointer value T *end;//points to element one past end T *begin;//points to start of allocated array unsigned length;//length of sequence public: Iter() { ptr = end = begin = NULL; length = 0; } Iter(T *p, T *first, T *last) { ptr = p; end = last; begin = first; length = last - first; } unsigned size() { return length; } T &operator*()//why return T& { if((ptr >= end) || (ptr < begin)) throw OutOfRangeExc(); return *ptr; } T *operator->()//??how to use?? { if((ptr >= end) || (ptr < begin)) throw OutOfRangeExc(); return ptr; } //prefix ++ Iter operator++() { ptr++; return *this; } Iter operator--() { ptr--; return *this; } //postfix ++; Iter operator++(int notused) { T *tmp = ptr; ptr++; return Iter<T>(tmp, begin, end); } Iter operator--(int notused) { T *tmp = ptr; ptr--; return Iter<T>(tmp, begin, end); } T &operator[](int i) { if((i < 0) || (i >= (end - begin))) throw OutOfRangeExc(); return ptr[i]; } bool operator==(Iter op2) { return ptr == op2.ptr; } bool operator!=(Iter op2) { return ptr != op2.ptr; } bool operator>(Iter op2) { return ptr > op2.ptr; } bool operator>=(Iter op2) { return ptr >= op2.ptr; } bool operator<(Iter op2) { return ptr < op2.ptr; } bool operator<=(Iter op2) { return ptr <= op2.ptr; } Iter operator-(int n)//no out of range check?? { ptr -= n; return *this; } int operator-(Iter<T> &itr2) { return ptr - itr2.ptr; } }; template <class T> class GCInfo { public: unsigned refcount; T *memPtr; unsigned arraySize;//size of memPtr bool isArray;//is points to array GCInfo(T *mPtr, unsigned size = 0) { refcount = 1; memPtr = mPtr; if(size != 0) isArray = true; else isArray = false; arraySize = size; } }; //this is needed by the STL list class template<class T> bool operator==(const GCInfo<T> &ob1, const GCInfo<T> &ob2) { return (ob1.memPtr == ob2.memPtr); } template <class T, int size = 0> class GCPtr { static list<GCInfo<T> > gclist; T *addr; bool isArray; unsigned arraySize; static bool first; typename list<GCInfo<T> >::iterator findPtrInfo(T *ptr); public: typedef Iter<T> GCiterator; GCPtr(T *t = NULL) { if(first) atexit(shutdown);//register shutdown() as an exit function first = false; typename list<GCInfo<T> >::iterator p; p = findPtrInfo(t); if(p != gclist.end()) p->refcount++; else { GCInfo<T> gcObj(t, size); gclist.push_front(gcObj); } addr = t; arraySize = size; if(size > 0) isArray = true; else isArray = false; #ifdef DISPLAY cout<<"Constructing GCPtr."; if(isArray) cout<<"size is "<<arraySize<<endl; else cout<<endl; #endif } //copy constructor GCPtr(const GCPtr &ob) { typename list<GCInfo<T> >::iterator p; p = findPtrInfo(ob.addr); p->refcount++; addr = ob.addr; arraySize = ob.arraySize; if(arraySize > 0) isArray = true; else isArray = false; #ifdef DISPLAY cout<<"Constructing copy."; if(isArray) cout<<"size is "<<arraySize<<endl; else cout<<endl; #endif } ~GCPtr(); static bool collect(); T *operator=(T *t); GCPtr &operator=(GCPtr &rv); T &operator*() { return *addr; } T *operator->()//???? { return addr; } T &operator[](int i) { return addr[i]; } operator T*() { return addr; } //return an iter to the start of the allocated memory Iter<T> begin() { int Size; if(isArray) Size = arraySize; else Size = 1; return Iter<T>(addr, addr, addr + Size); } Iter<T> end() { int Size; if(isArray) Size = arraySize; else Size = 1; return Iter<T>(addr + Size, addr, addr + Size); } static int gclistSize() { return gclist.size(); } static void showlist(); static void shutdown(); }; template<class T, int size> list<GCInfo<T> > GCPtr<T, size>::gclist; template<class T, int size> bool GCPtr<T, size>::first = true; template<class T, int size> GCPtr<T, size>::~GCPtr() { typename list<GCInfo<T> >::iterator p; p = findPtrInfo(addr); if(p->refcount != 0) p->refcount--; #ifdef DISPLAY cout<<"/nGCPtr going out of scope./n"; #endif collect(); } template<class T, int size> bool GCPtr<T, size>::collect() { bool memfreed = false; #ifdef DISPLAY cout<<"Before garbage collection for "; showlist(); #endif typename list<GCInfo<T> >::iterator p; do { for(p = gclist.begin(); p != gclist.end(); p++) { if(p->refcount > 0) continue; memfreed = true; gclist.remove(*p); if(p->memPtr) { if(p->isArray) { #ifdef DISPLAY cout<<"Deleting array of size "<<p->arraySize<<endl; #endif delete [] p->memPtr; } else { #ifdef DISPLAY cout<<"Deleting:"<<*(T*)p->memPtr<<endl; #endif delete p->memPtr; } }//if(p->memPtr) break; }//for }while(p != gclist.end()); #ifdef DISPLAY cout<<"After garbage collection for "; showlist(); #endif return memfreed; } template<class T, int size> T* GCPtr<T, size>::operator =(T *t) { typename list<GCInfo<T> >::iterator p; p = findPtrInfo(addr); p->refcount--; p = findPtrInfo(t); if(p != gclist.end()) p->refcount++; else { GCInfo<T> gcObj(t, size); gclist.push_front(gcObj); } addr = t; return t; } template<class T, int size> GCPtr<T, size> &GCPtr<T, size>::operator =(GCPtr &rv) { typename list<GCInfo<T> >::iterator p; p = findPtrInfo(addr); p->refcount--; p = findPtrInfo(rv.addr); p->refcount++; addr = rv.addr; return rv; } template<class T, int size> void GCPtr<T, size>::showlist() { typename list<GCInfo<T> >::iterator p; cout<<"gclist <"<<typeid(T).name()<<", "<<size<<">:/n"; cout<<"memPtr refcount value/n"; if(gclist.begin() == gclist.end()) { cout<<" --Empty--/n/n"; return; } for(p = gclist.begin(); p != gclist.end(); p++) { cout<<"["<<(void*)p->memPtr<<"]"<<" "<<p->refcount<<" "; if(p->memPtr) cout<<" " << *p->memPtr; else cout <<"--"; cout<<endl; } cout<<endl; } template<class T, int size> typename list<GCInfo<T> >::iterator GCPtr<T, size>::findPtrInfo(T *ptr) { typename list<GCInfo<T> >::iterator p; for( p = gclist.begin(); p !=gclist.end(); p++) if(p->memPtr == ptr) return p; return p; } template<class T, int size> void GCPtr<T, size>::shutdown() { if(gclistSize() == 0) return; typename list<GCInfo<T> >::iterator p; for(p = gclist.begin(); p != gclist.end(); p++) p->refcount = 0; #ifdef DISPLAY cout<<"Befor collecting for shudown() for "<<typeid(T).name()<<"/n"; #endif collect(); #ifdef DISPLAY cout<<"After collecting for shudown() for "<<typeid(T).name()<<"/n"; #endif } #endif Test cases: int allocate_single() { GCPtr<int> p; GCPtr<int> q; try { p = new int(10); q = new int(11); cout<<"Value at p is:"<<*p<<endl; cout<<"Value at q is:"<<*q<<endl; cout<<"Before entering block./n"; { GCPtr<int> r = new int(12); cout<<"Value at r is:"<<*r<<endl; }//block cout<<"After exiting block./n"; }catch(bad_alloc exc) { cout<<"Allocation failure!/n"; return 1; } cout<<"Done/n"; return 0; } int allocate_discard() { GCPtr<int> p; try { p = new int(1); p = new int(2); p = new int(3); GCPtr<int>::collect(); cout << "*p: " << *p << endl; }catch(bad_alloc exc) { cout<<"Allocation failure!"; return 1; } return 0; } int allocate_array() { try { // Create a GCPtr to an allocated array of 10 ints. GCPtr<int, 10> ap = new int[10]; // Give the array some values using array indexing. for(int i=0; i < 10; i++) ap[i] = i; // Now, show the contents of the array. for(int i=0; i < 10; i++) cout << ap[i] << " "; cout << endl; } catch(bad_alloc exc) { cout << "Allocation failure!/n"; return 1; } return 0; } int access_array_by_iterator() { try { GCPtr<int, 10> ap = new int[10]; GCPtr<int>::GCiterator itr = ap.begin(); for(int i=0; i < itr.size(); i++) itr[i] = i; for(itr = ap.begin(); ; itr++)//itr != ap.end() cout<<*itr<<" "; cout << endl; } catch(bad_alloc exc) { cout << "Allocation failure!/n"; return 1; } catch(OutOfRangeExc exc) { cout << "Out of range access!/n"; return 1; } return 0; } class MyClass { int a, b; public: double val; MyClass() { a = b = 0; } MyClass(int x, int y) { a = x; b = y; val = 0.0; } ~MyClass() { cout << "Destructing MyClass(" << a << ", " << b << ")/n"; } int sum() { return a + b; } friend ostream &operator<<(ostream &strm, MyClass &obj); }; // An overloaded inserter to display MyClass. ostream &operator<<(ostream &strm, MyClass &obj) { strm << "(" << obj.a << " " << obj.b << ")"; return strm; } int allocate_class() { GCPtr<MyClass> ob; ob = new MyClass(3,4); cout << *ob << endl; ob = new MyClass(11, 21); cout << *ob << endl; cout << "Sum is : " << ob->sum() << endl; ob->val = 5; cout << "ob->val:" << ob->val << endl; cout << "ob" << *ob << endl; return 0; }