TITLE: An interesting new/delete scheme

PROBLEM: maxtal@physics.su.OZ.AU (John Max Skaller), 29 Jun 93

	A solution requires a 'smart delete' that can figure
out how an object was allocated, and deallocate it accordingly.

	Again: a good solution would be well appreciated,
especially one in the existing language. Anyone?


RESPONSE: jimad@microsoft.com (Jim Adcock), 30 Jun 93
	  Microsoft Corporation

Obviously one must somehow mark the allocation such that the correct
deallocation can be performed via the one available delete function.
Clearly a variety of time/space tradeoffs are available.  Below find
the trivial and fast tradeoff of "marking" the allocation with the
address of the particular "free'ing" function to be called from
operator delete.  Two different flavors of new are presented for
example, one just mallocs, the other records and echos a variety
of debugging information.  Corresponding "free" routines are presented
which automatically get called from the one delete.  Both news and
both free are presented in the base class, but that need not be the
case.  Similar global new/free approaches are possible.



#include <malloc.h>
#include <assert.h>
#include <stddef.h>
#include <iostream.h>

typedef void FDEL(void* p, size_t size);
typedef FDEL* PFDEL;

class A
{
	int a;
	static void sfree(void* p, size_t size);
	static void sfreedebug(void* p, size_t size);
public:
	virtual ~A() {}
	void* operator new(size_t size);
	void operator delete(void* p, size_t size);
	void* operator new(size_t size, int iline, char* szfile); // debug version
};

void A::operator delete(void* p, size_t size)
{
	char* pb = (char*) p;
	pb -= sizeof(PFDEL);
	PFDEL pfdel = *(PFDEL*)pb;
	(*pfdel)(pb, size);
}

void A::sfree(void* p, size_t size)
{
	free(p);
}

void* A::operator new(size_t size)
{
	char* pb = (char*) malloc(size + sizeof(PFDEL));
	*(PFDEL*)pb = &sfree;
	return (pb + sizeof(PFDEL));
}

struct DEBUGHDR
{
	size_t size;
	int iline;
	char* szfile;
	PFDEL pfdel;
};

void A::sfreedebug(void* p, size_t size)
{
	char* pb = (char*) p;
	pb += (sizeof(PFDEL) - sizeof(DEBUGHDR));
	DEBUGHDR* phdr = (DEBUGHDR*) pb;

	assert(size == phdr->size);

	cout << "freeing " << phdr->size 
		<< " bytes allocated at line " << phdr->iline
		<< " in file " << phdr->szfile << "\n";

	free(pb);
}

void* A::operator new(size_t size, int iline, char* szfile)
{
	char* pb = (char*) malloc(size + sizeof(DEBUGHDR));
	DEBUGHDR* phdr = (DEBUGHDR*) pb;
	phdr->size = size;
	phdr->iline = iline;
	phdr->szfile = szfile;
	phdr->pfdel = &sfreedebug;

	cout << "new'ing " << phdr->size 
		<< " bytes allocated at line " << phdr->iline
		<< " in file " << phdr->szfile << "\n";

	return (pb + sizeof(DEBUGHDR));
}

class B : public A
{
	double b;
};

main()
{
	A* pa1 = new A;
	B* pb1 = new B;
	A* pa2 = new(__LINE__, __FILE__) A;
	B* pb2 = new(__LINE__, __FILE__) B;

	delete pa1;
	delete pb1;
	delete pa2;
	delete pb2;

	return 0;
}


