Selected C Example 20

 <  Free Open Study  >  

Selected C++ Example #20

 // Chapter 9 Example #2  // This C++ example illustrates the implementation of garbage // collection in C++. Garbage collection in C++ typically // revolves around a memory handler function that ''knows'' // which classes in the system are hoarding memory. The memory // handler knows which classes are hoarding memory because the // author of the application overloaded the new and delete // functions for the class in question. // In this example, we have a LinkedList class, which contains // Node objects. The Node class has overloaded its standard // allocator and deallocator (i.e., operators new and delete) // to hoard recyclable nodes on a freelist (a class variable) // The Node class has a free_garbage class method, which users // of the class can call. In this example, our memory handler, // called free_garbage, detects that memory has run out and // tells the Node class to put the memory back. #include <iostream.h> #include <new.h> #include <stdlib.h> #include <string.h> typedef int DATUM; // The memory handler for the application. void garbage_collect(); // Notice that the Node class is granting friendship to the // LinkedList class. Granting friendship to a class or method // is typically considered bad style since it weakens data // hiding. In this example, it is allowed since the Node class // is really an internal implementation detail of the LinkedList. // To force the LinkedList class to use accessor methods for // each access would overly convolute the code of the LinkedList // with items such as ''head->set_next(head->get_next())'' // instead of the much more readable ''head = head->next''. class Node {      DATUM data;      Node* next;      static Node* freelist;      friend class LinkedList; public:      Node(DATUM&);      void* operator new(size_t);      void operator delete(void*);      static int free_garbage();      static void print_freelist(); }; // The definition of the class variable ''freelist'' attached //to the Node class. Node* Node::freelist = NULL; // The overloaded new operator (the standard allocator) will // first try to recycle a node before going to the heap and // getting one the expensive way. void* Node::operator new(size_t sz) {      Node* p; // First try to get a node off the freelist.      if (freelist != NULL) {           p = freelist;           freelist = freelist->next;      }      else { // If that doesn't work, get one the old-fashioned, expensive // way by making a trip to the heap.            p = (Node*) new char[sz];       }       return(p); } // Be sure that ''delete 0'' works properly (a NOP), // then add the node to the freelist for later recycling. void Node::operator delete(void* p) {      if (p != NULL) {            ((Node*) p) ->next = freelist;            freelist = (Node*) p;      } } // The constructor for Node simply initializes the two data // members, regardless of whether or not it is a recycled node. Node::Node(DATUM& new_data) {      data = new_data;      next = NULL; } // This class method is used for diagnostics. It prints the // current addresses out on the Node's freelist. void Node::print_freelist() {      Node* temp = freelist;      cout << ''Freelist: '';      while (temp != NULL) {           cout << temp << '' '';           temp = temp->next;      }      cout << ''\n''; } // This class function will throw away the freelist of // nodes if a garbage-collection handler function // requests it. Since nodes have an overloaded delete // operator, the global delete must be called. Note the use // of the scope resolution operator. This function returns // the number of bytes it put back on the heap. int Node::free_garbage() {      Node* temp;       int counter = 0;       while (freelist != NULL) {            temp = freelist;            freelist = freelist->next; // Must use global delete to prevent infinite // recursion between deleting a node off of the // freelist and the overloaded delete operator putting // the node back on the freelist.            ::delete temp;            counter++;       }       return(counter*sizeof(Node)); } // The LinkedList class is a user of Nodes. Its constructor // and destructor call the overloaded new and delete of the // Node class. Use of LinkedList objects results in a Freelist // of Node objects stashed away in the Node class. class LinkedList {      Node* head;      int length; public:      LinkedList();      LinkedList(DATUM);      ~LinkedList();      int insert(DATUM);      int remove(DATUM);      void traverse() const; }; LinkedList::LinkedList() {      head = NULL;      length = 0; } LinkedList::LinkedList(DATUM first_item) {      head = new Node(first_item);      length = 1; } LinkedList::~LinkedList() {      Node* temp;      while (head != NULL) {          temp = head;          head = head->next;          delete temp;      } } int LinkedList::insert(DATUM new_item) {      Node* temp = head;      if (temp == NULL) {           head = new Node(new_item);      }      else {           while(temp->next != NULL) {                     temp = temp->next;           }           temp->next = new Node(new_item);      }      return(++length); } int LinkedList::remove(DATUM bad_item) {      Node* temp = head;      if (temp == NULL) {           return(0);      }      if (head->data == bad_item) {           head = head->next;           length--;           delete temp;      }      else {           while (temp->next != NULL&&                       temp->next->data != bad_item){                      temp = temp->next;           }           if (temp->next == NULL) {                      return(0);           }           else {                      Node* p = temp->next;                      temp->next = temp->next->next;                      length--;                      delete p;           }     } return(1); } void LinkedList::traverse()const {       Node* temp = head;       cout << ''('';       while (temp != NULL) {            cout << temp->data << '''';            temp = temp->next;       }       cout << '')\n''; } // The main function first installs our memory handler. // It then works with a number of LinkedList objects, which // results in a freelist of nodes. We attempt to allocate // an unallocatable amount of memory. The new operator for // the array of characters is called. It calls the equivalent // of malloc, which fails. New detects the failure and checks if // there is a memory handler. There is one installed // (garbage_collect), so we execute it and try malloc again, // hoping for success. The hope is that the garbage collector // will free enough memory so that the second attempt by new // to allocate the memory is successful. In this example, the // second attempt fails. The memory handler detects that no // additional space has been freed and thus exits from the // application, preventing infinite attempts to free memory even // when there is none to free. void main() {      set_new_handler(garbage_collect);      LinkedList a;      LinkedList b(100);      a.traverse();  b.traverse();      a.insert(1);   a.insert(2);      a.insert(3);   a.insert(4);      a.insert(5);   a.insert(6);      b.insert(200); b.insert(300);      b.insert(400); b.insert(500);      b.insert(600); b.insert(700);      a.traverse();b.traverse();      Node::print_freelist();      a.remove(1); b.remove(100);      a.traverse();b.traverse();      a.remove(6); b.remove(700);      a.traverse();b.traverse();      a.remove(4); b.remove(400);      a.traverse();b.traverse();      Node::print_freelist();      a.insert(99); a.insert(199);      b.insert(-45);b.insert(-44);      a.traverse(); b.traverse();      Node::print_freelist();      char* big_buf = NULL; // This block is impossible to retrieve. New will fail and will // call our handler, which tells the Node class to free // its horded nodes. The call to new still fails, so we exit // the application.      big_buf = new char[65530L];      strcpy(big_buf, ''Arthur Riel'');      cout << ''big_buf = '' << big_buf <<''.\n''; } // The garbage-collection routine is a cornerstone in this // example. It possesses knowledge of what element of the // application is hoarding memory. When the heap is out of // space, this routine tells the hoarders to put their memory // back on the heap. If this routine cannot find any memory to // free, it bails out. void garbage_collect() {      int space_freed; // Get some space freed on the heap by telling the hoarding // Node class to put its memory back.       space_freed = Node::free_garbage(); // If there's nothing to free, simply fail. Otherwise, // return and let new try again.       if (!space_freed){            cerr << ''Fatal Memory Error!!!\n'';            exit(-1);       } } 
 <  Free Open Study  >  


Object-Oriented Design Heuristics
Object-Oriented Design Heuristics (paperback)
ISBN: 0321774965
EAN: 2147483647
Year: 1996
Pages: 180

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net