home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Ebooks / Thinking in C++ V2 / C12 / RefcountTrace.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-25  |  3.3 KB  |  131 lines

  1. //: C12:RefcountTrace.cpp
  2. // From Thinking in C++, 2nd Edition
  3. // Available at http://www.BruceEckel.com
  4. // (c) Bruce Eckel 1999
  5. // Copyright notice in Copyright.txt
  6. // Refcount.cpp w/ trace info
  7. #include "../require.h"
  8. #include <cstring>
  9. #include <fstream>
  10. using namespace std;
  11.  
  12. ofstream out("rctrace.out");
  13.  
  14. class Counted {
  15.   class MemBlock {
  16.     static const int size = 100;
  17.     char c[size];
  18.     int refcount;
  19.     static int blockcount;
  20.     int blocknum;
  21.   public:
  22.     MemBlock() {
  23.       memset(c, 1, size);
  24.       refcount = 1;
  25.       blocknum = blockcount++;
  26.     }
  27.     MemBlock(const MemBlock& rv) {
  28.       memcpy(c, rv.c, size);
  29.       refcount = 1;
  30.       blocknum = blockcount++;
  31.       print("copied block");
  32.       out << endl;
  33.       rv.print("from block");
  34.     }
  35.     ~MemBlock() {
  36.       out << "\tdestroying block "
  37.           << blocknum << endl;
  38.     }
  39.     void print(const char* msg = "") const {
  40.       if(*msg) out << msg << ", ";
  41.       out << "blocknum:" << blocknum;
  42.       out << ", refcount:" << refcount;
  43.     }
  44.     void attach() { ++refcount; }
  45.     void detach() {
  46.       require(refcount != 0);
  47.       // Destroy object if no one is using it:
  48.       if(--refcount == 0) delete this;
  49.     }
  50.     int count() const { return refcount; }
  51.     void set(char x) { memset(c, x, size); }
  52.     // Conditionally copy this MemBlock.
  53.     // Call before modifying the block; assign
  54.     // resulting pointer to your block;
  55.     MemBlock* unalias() {
  56.       // Don't duplicate if not aliased:
  57.       if(refcount == 1) return this;
  58.       --refcount;
  59.       // Use copy-constructor to duplicate:
  60.       return new MemBlock(*this);
  61.     }
  62.   }* block;
  63.   static const int sz = 30;
  64.   char ident[sz];
  65. public:
  66.   Counted(const char* id = "tmp") {
  67.     block = new MemBlock; // Sneak preview
  68.     strncpy(ident, id, sz);
  69.   }
  70.   Counted(const Counted& rv) {
  71.     block = rv.block; // Pointer assignment
  72.     block->attach();
  73.     strncpy(ident, rv.ident, sz);
  74.     strncat(ident, " copy", sz - strlen(ident));
  75.   }
  76.   void unalias() { block = block->unalias(); }
  77.   void addname(const char* nm) {
  78.     strncat(ident, nm, sz - strlen(ident));
  79.   }
  80.   Counted& operator=(const Counted& rv) {
  81.     print("inside operator=\n\t");
  82.     if(&rv == this) {
  83.       out << "self-assignment" << endl;
  84.       return *this;
  85.     }
  86.     // Clean up what you're using first:
  87.     block->detach();
  88.     block = rv.block; // Like copy-constructor
  89.     block->attach();
  90.     return *this;
  91.   }
  92.   // Decrement refcount, conditionally destroy
  93.   ~Counted() {
  94.     out << "preparing to destroy: " << ident
  95.         << "\n\tdecrementing refcount ";
  96.     block->print();
  97.     out << endl;
  98.     block->detach();
  99.   }
  100.   // Copy-on-write:
  101.   void write(char value) {
  102.     unalias();
  103.     block->set(value);
  104.   }
  105.   void print(const char* msg = "") {
  106.     if(*msg) out << msg << " ";
  107.     out << "object " << ident << ": ";
  108.     block->print();
  109.     out << endl;
  110.   }
  111. };
  112.  
  113. int Counted::MemBlock::blockcount = 0;
  114.  
  115. int main() {
  116.   Counted A("A"), B("B");
  117.   Counted C(A);
  118.   C.addname(" (C) ");
  119.   A.print();
  120.   B.print();
  121.   C.print();
  122.   B = A;
  123.   A.print("after assignment\n\t");
  124.   B.print();
  125.   out << "Assigning C = C" << endl;
  126.   C = C;
  127.   C.print("calling C.write('x')\n\t");
  128.   C.write('x');
  129.   out << "\n exiting main()" << endl;
  130. } ///:~
  131.