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
Wrap
C/C++ Source or Header
|
1994-11-01
|
6KB
|
238 lines
////////////////////////////////////////////////////////////////
// EX.CPP
// Written by Paul DiLascia for Microsoft Systems Journal 1994
//
// This program illustrates how to avoid losing memory when exceptions
// are thrown. It comes in two flavors: the "GOOD" and "bad" versions.
// To compile the bad version, type: bcc ex.cpp
// To compile the good version, type: bcc -DGOOD ex.cpp
// (requires Borland 4.0 C++ compiler)
//
#include <malloc.h>
#include <stdio.h>
#include <assert.h>
//////////////////
// Primitive memory tracking
//
const MAXALLOCPTRS = 50; // size of alloc tracking array
static void* AllocPtrs[MAXALLOCPTRS]; // alloc tracking array
static size_t AllocSizes[MAXALLOCPTRS]; // size of tracking array
static int AllocCount = 0; // total num allocations
//////////////////
// Override global new operator to keep track of allocations.
//
void* operator new(size_t size)
{
void *p = calloc(size, 1);
assert(p);
// Store pointer in tracking array if there's room
for (int i=0; i<MAXALLOCPTRS; i++) {
if (AllocPtrs[i]==NULL) {
AllocPtrs[i] = p;
AllocSizes[i] = size;
break;
}
}
AllocCount++; // increment total count
return p;
}
//////////////////
// Override global delete operator to keep track of allocations.
//
void operator delete(void * p)
{
free(p);
// If this is one of the allocations tracked,
// remove it from tracking array.
//
for (int i=0; i<MAXALLOCPTRS; i++) {
if (AllocPtrs[i]==p) {
AllocPtrs[i] = NULL;
break;
}
}
AllocCount--; // decrement total allocations extant
}
////////////////
// Base class mother-of-all-objects.
// Destructor must be virtual for "Deleter" class to work
//
class Object {
public:
virtual ~Object() { } // virtual destructor
};
//////////////////
// Some other object derived from base class Object.
// This example allocates its own array from the free store.
//
class CharArray : public Object {
char* array; // allocated by constructor
enum { arraysize=512 }; // array size in bytes
public:
CharArray() { array = new char [arraysize]; }
~CharArray() { delete [] array; }
};
//////////////////
// Divide by zero exception class, thrown by Divide function.
//
class DivideByZero : public Object {
public:
enum ErrType { DivByZero=1, ZeroOverZero } errType;
DivideByZero(ErrType e) : errType(e) { }
};
#ifdef GOOD
//////////////////
// "Deleter" class is used in the "good" version of the program to
// delete objects that might otherwise be left as garbage when an
// exception is thrown.
//
// This class requires a constructor for each different kind of object
// that might be deleted. Since Object has a virtual destructor,
// only one Deleter constrcutor is required for all Object-derived classes.
//
class Deleter {
void* ptr; // object to be deleted
enum { tvoid, tobject } iObjType; // type
public:
Deleter(void *pv); // "raw" memory
Deleter(Object* pobj); // object-derived classes
// Deleter(Other* poth); // add for other classes used...
~Deleter();
};
//////////////////
// Deleter constructors are straightforward
//
Deleter::Deleter(void *pv) : ptr(pv), iObjType(tvoid)
{
}
Deleter::Deleter(Object* pobj) : ptr(pobj), iObjType(tobject)
{
}
//////////////////
// Destructor destroys object "tracked" based on type.
//
Deleter::~Deleter()
{
if (iObjType==tvoid)
delete ptr; // delete as void*
else if (iObjType==tobject)
delete (Object*)ptr; // delete as Object*
else {
assert(0);
}
}
#endif
//////////////////
// Low-level divide function may throw an exception.
//
float Divide(float numerator, float denominator)
{
if (denominator==0) { // Oops!
if (numerator==0)
throw DivideByZero(DivideByZero::ZeroOverZero);
else
throw DivideByZero(DivideByZero::DivByZero);
}
return numerator/denominator;
}
//////////////////
// DoDivide divides two numbers.
// It acts as the "intermediary" function that allocates storage
// which may be lost when an exception is thrown across the great divide
// (pardon the pun).
//
float DoDivide(float numerator, float denominator)
{
// The following objects never get deleted in the bad version,
// if Divide throws an exception:
//
char* p = new char[40]; // ordinary character array
CharArray *po = new CharArray; // object created in free store
// The following object is destroyed even in the bad version,
// because it's created on the stack.
//
CharArray o;
#ifdef GOOD
// "Good" version of program uses Deleter class to
// ensure memory objects are deleted
//
Deleter d1(p); // delete character array p
Deleter d2(po); // delete object pointer po
#endif
// Do the divide:
float result = Divide(numerator, denominator);
#ifndef GOOD
// Bad version of program uses delete to destroy allocations--But
// these lines are never reached if Divide throws an exception!
//
delete [] p; // may never get deleted
delete po; // ditto
#endif
return result;
}
//////////////////
// Some numbers to divide
//
const NPAIRS=5;
float DivPairs[NPAIRS][2] =
{
{ 10, 2 }, { 3.14159, 2 }, { 10, 0 }, { 0, 0 }, { 2.71828, 2.71828 }
};
//////////////////
// Main program loop:
// Display results of dividing above pairs.
//
int main()
{
assert(AllocCount==0); // should have no allocations to start
for (int i=0; i<NPAIRS; i++) {
float numerator = DivPairs[i][0];
float denominator = DivPairs[i][1];
printf("%f \t/ %f \t= ", numerator, denominator);
try {
float result = DoDivide(numerator, denominator);
printf("%f\n", result);
} catch (DivideByZero dbz) {
printf("DivideByZero(%d)\n", dbz.errType);
}
}
// Display nasty message of any garbage is left
//
if (AllocCount!=0) {
printf("\nGARBAGE LEFT! [%d objects]:\n", AllocCount);
for (int i=0; i<MAXALLOCPTRS; i++) {
if (AllocPtrs[i]!=NULL)
printf(" Array %p [%d]\n", AllocPtrs[i], AllocSizes[i]);
}
}
return 0;
}