home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 038 / cppq1194.exe / EX.CPP
C/C++ Source or Header  |  1994-11-01  |  6KB  |  238 lines

  1. ////////////////////////////////////////////////////////////////
  2. // EX.CPP 
  3. // Written by Paul DiLascia for Microsoft Systems Journal 1994
  4. //
  5. // This program illustrates how to avoid losing memory when exceptions
  6. // are thrown. It comes in two flavors: the "GOOD" and "bad" versions.
  7. // To compile the bad version, type:            bcc ex.cpp
  8. // To compile the good version, type:            bcc -DGOOD ex.cpp
  9. // (requires Borland 4.0 C++ compiler)
  10. //
  11.  
  12. #include <malloc.h>
  13. #include <stdio.h>
  14. #include <assert.h>
  15.  
  16. //////////////////
  17. // Primitive memory tracking
  18. //
  19. const MAXALLOCPTRS = 50;                        // size of alloc tracking array
  20. static void*    AllocPtrs[MAXALLOCPTRS];    // alloc tracking array
  21. static size_t    AllocSizes[MAXALLOCPTRS];    // size of tracking array
  22. static int        AllocCount = 0;                // total num allocations
  23.  
  24. //////////////////
  25. // Override global new operator to keep track of allocations.
  26. //
  27. void* operator new(size_t size)
  28. {
  29.     void *p = calloc(size, 1);
  30.     assert(p);
  31.  
  32.     // Store pointer in tracking array if there's room
  33.     for (int i=0; i<MAXALLOCPTRS; i++) {    
  34.         if (AllocPtrs[i]==NULL) {
  35.             AllocPtrs[i] = p;
  36.             AllocSizes[i] = size;
  37.             break;
  38.         }
  39.     }
  40.     AllocCount++;                // increment total count
  41.     return p;
  42. }
  43.  
  44. //////////////////
  45. // Override global delete operator to keep track of allocations.
  46. //
  47. void operator delete(void * p)
  48. {
  49.     free(p);
  50.  
  51.     // If this is one of the allocations tracked, 
  52.     // remove it from tracking array.
  53.     //
  54.     for (int i=0; i<MAXALLOCPTRS; i++) {
  55.         if (AllocPtrs[i]==p) {
  56.             AllocPtrs[i] = NULL;
  57.             break;
  58.         }
  59.     }
  60.     AllocCount--;                // decrement total allocations extant
  61. }
  62.  
  63. ////////////////
  64. // Base class mother-of-all-objects.
  65. // Destructor must be virtual for "Deleter" class to work
  66. //
  67. class Object {
  68. public:
  69.     virtual ~Object() { }        // virtual destructor
  70. };
  71.  
  72. //////////////////
  73. // Some other object derived from base class Object.
  74. // This example allocates its own array from the free store.
  75. //
  76. class CharArray : public Object {
  77.     char* array;                    // allocated by constructor
  78.     enum { arraysize=512 };    // array size in bytes
  79. public:
  80.     CharArray()        { array = new char [arraysize]; }
  81.     ~CharArray()    { delete [] array; }
  82. };
  83.  
  84. //////////////////
  85. // Divide by zero exception class, thrown by Divide function.
  86. //
  87. class DivideByZero : public Object {
  88. public:
  89.     enum ErrType { DivByZero=1, ZeroOverZero } errType;
  90.     DivideByZero(ErrType e) : errType(e) { }
  91. };
  92.  
  93. #ifdef GOOD
  94.  
  95. //////////////////
  96. // "Deleter" class is used in the "good" version of the program to
  97. // delete objects that might otherwise be left as garbage when an 
  98. // exception is thrown.
  99. //
  100. // This class requires a constructor for each different kind of object
  101. // that might be deleted. Since Object has a virtual destructor,
  102. // only one Deleter constrcutor is required for all Object-derived classes.
  103. //
  104. class Deleter {
  105.     void* ptr;                                    // object to be deleted
  106.     enum { tvoid, tobject } iObjType;    // type
  107. public:
  108.     Deleter(void *pv);                        // "raw" memory
  109.     Deleter(Object* pobj);                    // object-derived classes
  110. //    Deleter(Other* poth);                    // add for other classes used...
  111.     ~Deleter();
  112. };
  113.  
  114. //////////////////
  115. // Deleter constructors are straightforward
  116. //
  117. Deleter::Deleter(void *pv) : ptr(pv), iObjType(tvoid) 
  118. {
  119. }
  120. Deleter::Deleter(Object* pobj) : ptr(pobj), iObjType(tobject) 
  121. {
  122. }
  123.  
  124. //////////////////
  125. // Destructor destroys object "tracked" based on type.
  126. //
  127. Deleter::~Deleter()
  128. {
  129.     if (iObjType==tvoid)
  130.         delete ptr;                // delete as void*
  131.     else if (iObjType==tobject)
  132.         delete (Object*)ptr;    // delete as Object*
  133.     else {
  134.         assert(0);
  135.     }
  136. }
  137. #endif
  138.  
  139. //////////////////
  140. // Low-level divide function may throw an exception.
  141. //
  142. float Divide(float numerator, float denominator)
  143. {
  144.     if (denominator==0) {    // Oops!
  145.         if (numerator==0) 
  146.             throw DivideByZero(DivideByZero::ZeroOverZero);
  147.         else 
  148.             throw DivideByZero(DivideByZero::DivByZero);
  149.     }
  150.     return numerator/denominator;
  151. }
  152.  
  153. //////////////////
  154. // DoDivide divides two numbers.
  155. // It acts as the "intermediary" function that allocates storage
  156. // which may be lost when an exception is thrown across the great divide
  157. // (pardon the pun).
  158. //
  159. float DoDivide(float numerator, float denominator)
  160. {
  161.     // The following objects never get deleted in the bad version,
  162.     // if Divide throws an exception:
  163.     // 
  164.     char* p            = new char[40];        // ordinary character array
  165.     CharArray *po    = new CharArray;        // object created in free store
  166.  
  167.     // The following object is destroyed even in the bad version,
  168.     // because it's created on the stack.
  169.     // 
  170.     CharArray o;
  171.  
  172. #ifdef GOOD
  173.     // "Good" version of program uses Deleter class to 
  174.     // ensure memory objects are deleted
  175.     //
  176.     Deleter d1(p);                // delete character array p
  177.     Deleter d2(po);            // delete object pointer po
  178. #endif
  179.  
  180.     // Do the divide:
  181.     float result = Divide(numerator, denominator);
  182.  
  183. #ifndef GOOD
  184.     // Bad version of program uses delete to destroy allocations--But
  185.     // these lines are never reached if Divide throws an exception!
  186.     //
  187.     delete [] p;                // may never get deleted
  188.     delete po;                    // ditto
  189. #endif
  190.  
  191.     return result;
  192. }
  193.  
  194. //////////////////
  195. // Some numbers to divide
  196. //
  197. const NPAIRS=5;
  198. float DivPairs[NPAIRS][2] =
  199. {
  200.     { 10, 2 }, { 3.14159, 2 }, { 10, 0 }, { 0,  0 }, { 2.71828, 2.71828 }
  201. };
  202.  
  203. //////////////////
  204. // Main program loop: 
  205. // Display results of dividing above pairs.
  206. //
  207. int main()
  208. {
  209.     assert(AllocCount==0);    // should have no allocations to start
  210.  
  211.     for (int i=0; i<NPAIRS; i++) {
  212.         float numerator   = DivPairs[i][0];
  213.         float denominator = DivPairs[i][1];
  214.         printf("%f \t/ %f \t= ", numerator, denominator);
  215.  
  216.         try {
  217.             float result = DoDivide(numerator, denominator);
  218.             printf("%f\n", result);
  219.  
  220.         } catch (DivideByZero dbz) {
  221.             printf("DivideByZero(%d)\n", dbz.errType);
  222.         }
  223.     }
  224.  
  225.     // Display nasty message of any garbage is left
  226.     //
  227.     if (AllocCount!=0) {
  228.         printf("\nGARBAGE LEFT! [%d objects]:\n", AllocCount);
  229.         
  230.         for (int i=0; i<MAXALLOCPTRS; i++) {
  231.             if (AllocPtrs[i]!=NULL)
  232.                 printf(" Array %p [%d]\n", AllocPtrs[i], AllocSizes[i]);
  233.         }
  234.     }
  235.  
  236.     return 0;
  237. }
  238.