Herbert Schildt对C++垃圾回收机制的实现

原创 2005年05月23日 17:50:00
// A single-threaded garbage collector.  
  
#include <iostream>  
#include <list>  
#include <typeinfo>  
#include <cstdlib>
  
using namespace std;  
  
// To watch the action of the garbage collector, define DISPLAY.  
// #define DISPLAY  
  
// Exception thrown when an attempt is made to   
// use an Iter that exceeds the range of the   
// underlying object.  
//  
class OutOfRangeExc {  
  // Add functionality if needed by your application.  
};  
  
// An iterator-like class for cycling through arrays  
// that are pointed to by GCPtrs. Iter pointers  
// ** do not ** participate in or affect garbage  
// collection.  Thus, an Iter pointing to  
// some object does not prevent that object  
// from being recycled.  
//  
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;  
  }  
    
  // Return length of sequence to which this  
  // Iter points.  
  unsigned size() { return length; }  
  
  // Return value pointed to by ptr.  
  // Do not allow out-of-bounds access.
  T &operator*() {   
    if( (ptr >= end) || (ptr < begin) )  
      throw OutOfRangeExc();  
    return *ptr;  
  }  
  
  // Return address contained in ptr.  
  // Do not allow out-of-bounds access.
  T *operator->() {   
    if( (ptr >= end) || (ptr < begin) )  
      throw OutOfRangeExc();  
    return ptr;  
  }    
  
  // Prefix ++.  
  Iter operator++() {  
    ptr++;  
    return *this;  
  }  
  
  // Prefix --.  
  Iter operator--() {  
    ptr--;  
    return *this;  
  }  
  
  // Postfix ++.  
  Iter operator++(int notused) {  
    T *tmp = ptr;  
  
    ptr++;  
    return Iter<T>(tmp, begin, end);  
  }  
  
  // Postfix --.  
  Iter operator--(int notused) {  
    T *tmp = ptr;  
  
    ptr--;  
    return Iter<T>(tmp, begin, end);  
  }  
  
  // Return a reference to the object at the  
  // specified index. Do not allow out-of-bounds  
  // access.  
  T &operator[](int i) {  
    if( (i < 0) || (i >= (end-begin)) )  
      throw OutOfRangeExc();  
    return ptr[i];  
  }  
  
  // Define the relational operators.  
  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;  
  }  
  
  // Subtract an integer from an Iter.  
  Iter operator-(int n) {  
    ptr -= n;  
    return *this;  
  }  
  
  // Add an integer to an Iter.  
  Iter operator+(int n) {  
    ptr += n;  
    return *this;  
  }  
  
  // Return number of elements between two Iters.  
  int operator-(Iter<T> &itr2) {  
    return ptr - itr2.ptr;  
  }  
    
};  
  
  
// This class defines an element that is stored  
// in the garbage collection information list.   
//  
template <class T> class GCInfo {  
public:  
  unsigned refcount; // current reference count

  T *memPtr; // pointer to allocated memory  
  
  /* isArray is true if memPtr points  
     to an allocated array. It is false  
     otherwise. */  
  bool isArray; // true if pointing to array  
  
  /* If memPtr is pointing to an allocated  
     array, then arraySize contains its size */  
  unsigned arraySize; // size of array  
  
  // Here, mPtr points to the allocated memory.
  // If this is an array, then size specifies
  // the size of the array.  
  GCInfo(T *mPtr, unsigned size=0) {  
    refcount = 1;
    memPtr = mPtr;  
    if(size != 0)  
      isArray = true;  
    else  
      isArray = false;  
  
    arraySize = size;  
  }  
};  
  
// Overloading operator== allows GCInfos to be compared.  
// 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);  
}  
  
  
// GCPtr implements a pointer type that uses  
// garbage collection to release unused memory.  
// A GCPtr must only be used to point to memory  
// that was dynamically allocated using new.   
// When used to refer to an allocated array,  
// specify the array size.  
//  
template <class T, int size=0> class GCPtr {  

  // gclist maintains the garbage collection list.  
  static list<GCInfo<T> > gclist;  

  // addr points to the allocated memory to which  
  // this GCPtr pointer currently points.  
  T *addr;  
  
  /* isArray is true if this GCPtr points  
     to an allocated array. It is false  
     otherwise. */  
  bool isArray; // true if pointing to array  
  
  // If this GCPtr is pointing to an allocated  
  // array, then arraySize contains its size.  
  unsigned arraySize; // size of the array  

  static bool first; // true when first GCPtr is created

  // Return an iterator to pointer info in gclist.  
  typename list<GCInfo<T> >::iterator findPtrInfo(T *ptr);

public:  
  
  // Define an iterator type for GCPtr<T>.  
  typedef Iter<T> GCiterator;  
  
  // Construct both initialized and uninitialized objects.  
  GCPtr(T *t=NULL) {

    // Register shutdown() as an exit function. 
    if(first) atexit(shutdown);
    first = false;

    list<GCInfo<T> >::iterator p;

    p = findPtrInfo(t);

    // If t is already in gclist, then
    // increment its reference count. 
    // Otherwise, add it to the list.
    if(p != gclist.end()) 
      p->refcount++; // increment ref count
    else {
      // Create and store this entry.  
      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) {  
    list<GCInfo<T> >::iterator p;

    p = findPtrInfo(ob.addr); 
    p->refcount++; // increment ref count
  
    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  
  }  
  
  // Destructor for GCPTr. 
  ~GCPtr();  
  
  // Collect garbage.  Returns true if at least  
  // one object was freed.  
  static bool collect(); 
     
  // Overload assignment of pointer to GCPtr.  
  T *operator=(T *t); 
 
  // Overload assignment of GCPtr to GCPtr.  
  GCPtr &operator=(GCPtr &rv); 
 
  // Return a reference to the object pointed  
  // to by this GCPtr.  
  T &operator*() {  
    return *addr;  
  }  
  
  // Return the address being pointed to.  
  T *operator->() { return addr; }    
  
  // Return a reference to the object at the  
  // index specified by i.  
  T &operator[](int i) {  
    return addr[i];  
  }  
  
  // Conversion function to T *.  
  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);  
  }      
  
  // Return an Iter to one past the end of an allocated array.  
  Iter<T> end() {  
    int size;  
  
    if(isArray) size = arraySize;  
    else size = 1;  
  
    return Iter<T>(addr + size, addr, addr + size);  
  }  
  
  // Return the size of gclist for this type  
  // of GCPtr.  
  static int gclistSize() { return gclist.size(); }  
  
  // A utility function that displays gclist.  
  static void showlist(); 

  // Clear gclist when program exits. 
  static void shutdown(); 
};  
  
// Creates storage for the static variables
template <class T, int size>   
  list<GCInfo<T> > GCPtr<T, size>::gclist; 

template <class T, int size> 
  bool GCPtr<T, size>::first = true; 

// Destructor for GCPtr. 
template <class T, int size> 
GCPtr<T, size>::~GCPtr() {  
  list<GCInfo<T> >::iterator p;  
  
  p = findPtrInfo(addr);
  if(p->refcount) p->refcount--; // decrement ref count

  #ifdef DISPLAY  
    cout << "GCPtr going out of scope./n";
  #endif  

  // Collect garbage when a pointer goes out of scope.
  collect();  
  
  // For real use, you might want to collect  
  // unused memory less frequently, such as after  
  // gclist has reached a certain size, after a  
  // certain number of GCPtrs have gone out of scope,  
  // or when memory is low.  
}  
 
// Collect garbage.  Returns true if at least  
// one object was freed.  
template <class T, int size> 
bool GCPtr<T, size>::collect() {   
  bool memfreed = false;  
     
  #ifdef DISPLAY  
    cout << "Before garbage collection for ";  
    showlist();  
  #endif  

  list<GCInfo<T> >::iterator p;  
  do {  
  
    // Scan gclist looking for unreferenced pointers.  
    for(p = gclist.begin(); p != gclist.end(); p++) {  
      // If in-use, skip.
      if(p->refcount > 0) continue;  

      memfreed = true;  

      // Remove unused entry from gclist.
      gclist.remove(*p);  

      // Free memory unless the GCPtr is null.
      if(p->memPtr) {
        if(p->isArray) {  
          #ifdef DISPLAY  
            cout << "Deleting array of size "  
                 << p->arraySize << endl;  
          #endif  
          delete[] p->memPtr; // delete array  
        }  
        else {  
          #ifdef DISPLAY  
            cout << "Deleting: "  
                 << *(T *) p->memPtr << "/n";  
          #endif  
          delete p->memPtr; // delete single element  
        }  
      }

      // Restart the search.
      break;
    }

  } while(p != gclist.end());  
  
  #ifdef DISPLAY  
    cout << "After garbage collection for ";  
    showlist();  
  #endif  
  
  return memfreed;  
}  
 
// Overload assignment of pointer to GCPtr.  
template <class T, int size> 
T * GCPtr<T, size>::operator=(T *t) {  
  list<GCInfo<T> >::iterator p;  
  
  // First, decrement the reference count
  // for the memory currently being pointed to.
  p = findPtrInfo(addr);
  p->refcount--; 

  // Next, if the new address is already
  // existent in the system, increment its
  // count.  Otherwise, create a new entry
  // for gclist.
  p = findPtrInfo(t);
  if(p != gclist.end()) 
    p->refcount++; 
  else {
    // Create and store this entry.  
    GCInfo<T> gcObj(t, size);  
    gclist.push_front(gcObj);  
  }

  addr = t; // store the address.  
  
  return t;  
}

// Overload assignment of GCPtr to GCPtr.  
template <class T, int size> 
GCPtr<T, size> & GCPtr<T, size>::operator=(GCPtr &rv) {  
  list<GCInfo<T> >::iterator p;  

  // First, decrement the reference count
  // for the memory currently being pointed to.
  p = findPtrInfo(addr);
  p->refcount--;

  // Next, increment the reference count of
  // the new address.
  p = findPtrInfo(rv.addr);
  p->refcount++; // increment ref count

  addr = rv.addr;// store the address.  
 
  return rv;  
}  
 
// A utility function that displays gclist.  
template <class T, int size> 
void GCPtr<T, size>::showlist() {  
  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;  
} 

// Find a pointer in gclist.
template <class T, int size> 
typename list<GCInfo<T> >::iterator 
  GCPtr<T, size>::findPtrInfo(T *ptr) {  

  list<GCInfo<T> >::iterator p;  
  
  // Find ptr in gclist.  
  for(p = gclist.begin(); p != gclist.end(); p++) 
    if(p->memPtr == ptr) 
      return p;

  return p;  
}  

// Clear gclist when program exits. 
template <class T, int size>  
void GCPtr<T, size>::shutdown() { 

  if(gclistSize() == 0) return; // list is empty

  list<GCInfo<T> >::iterator p; 

  for(p = gclist.begin(); p != gclist.end(); p++) { 
    // Set all reference counts to zero 
    p->refcount = 0; 
  }
 
  #ifdef DISPLAY     
    cout << "Before collecting for shutdown() for " 
         << typeid(T).name() << "/n";   
  #endif 

  collect(); 
 
  #ifdef DISPLAY     
    cout << "After collecting for shutdown() for " 
         << typeid(T).name() << "/n";   
  #endif 
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

c++ 垃圾回收机制

  • 2008年09月28日 21:34
  • 181KB
  • 下载

GC垃圾回收机制

  • 2014年12月19日 14:53
  • 181KB
  • 下载

C++引用计数实现垃圾回收机制

原理:用一个数去统计指向堆中的无名对象指针的个数,由最后一个指针去释放其空间。为了保持同步,应该使这个数也只有一份。 简单实现如下 //SmartPtr.h #pragma once #inclu...

java垃圾回收机制

  • 2016年06月19日 07:57
  • 14KB
  • 下载

Java垃圾回收机制详解

  • 2011年11月19日 14:33
  • 199KB
  • 下载

C++实现垃圾回收机制

C++实现垃圾回收机制        我想讨论的问题是,如何让下面的代码正确无误: #include classHuman { public:     Human()     {  ...

Java垃圾回收机制

  • 2013年06月17日 01:07
  • 63KB
  • 下载

Java垃圾回收机制的学习和使用

  • 2011年07月27日 10:54
  • 26KB
  • 下载

C++为什么不加入垃圾回收机制

Java的爱好者们经常批评C++中没有提供与Java类似的垃圾回收(Gabage Collector)机制(这很正常,正如C++的爱好者有时也攻击Java没有这个没有那个,或者这个不行那个不够好),导...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Herbert Schildt对C++垃圾回收机制的实现
举报原因:
原因补充:

(最多只允许输入30个字)