[comp.lang.c++] Cfront problem with operator delete?

tom@sco.COM (Tom Kelly) (12/21/90)

In the program below I have an operator delete(void *, size_t) in
a base class (base).  I derive from that base class, inheriting new
and delete.  I expect the new and delete operators to be called with
the appropriate size of the derived objects.

It works fine for operator new().  However, the second argument to 
operator delete() is always the same, and reflects the size
of the base class.

According to E&S (ARM), p. 283:

	If the two argument style is used, operator delete() will be
	called with a second argument indicating the size of the
	object being deleted.  The size passed is determined by the
	destructor (if any) or by the (static) type of the pointer
	being deleted; that is, it will be correct either if the
	type of the pointer argument to the delete operator is
	the exact type of the object (and not, for example, just the
	type of base class) or if the type is that of a base class
	with a virtual destructor.

Since all my deletes are using the exact type of the object, I expect
delete to get the right size.

Am I mis-interpreting the ARM and doing something wrong, or is this
a bug in cfront?  If the code ifdef'd with FIX is compiled in, then
the program works and gets the expected answer.

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

class base {
public:
	void *operator new(size_t s);
	void operator delete(void *, size_t);
#ifdef FIX
	virtual ~base() {};
#endif
private:
	int key;
};

void *
base::operator new(size_t s)
{
	void *p;

	cout << "calling operator new for base, size " << dec << s << endl;
	p = malloc(s);
	cout << "allocated @ " << hex << p << endl;
	return p;
}

void
base::operator delete(void *p, size_t s)
{
	cout << "called operator delete for base @" << hex << p << dec <<
		" size " << s << endl;
	free(p);
	return;
}

class derived: public base {
public:
	int x;
	int y;
	derived(int a, int b): x(a), y(b) {};
};

class derived2: public base {
public:
	int a;
	char b[10];
};

main()
{
	derived *dp;
	base *bp;

	dp = new derived(5, 6);
	cout << dp->x << " " << dp->y << endl;

	bp = new base;
	derived2 *dp2 = new derived2;

	delete dp;
	delete dp2;
	delete bp;
}

Program Output (compiled -UFIX)

calling operator new for base, size 12
allocated @ 0x402aa4
5 6
calling operator new for base, size 4
allocated @ 0x402ab4
calling operator new for base, size 20
allocated @ 0x402abc
called operator delete for base @0x402aa4 size 4
called operator delete for base @0x402abc size 4
called operator delete for base @0x402ab4 size 4

Tom Kelly  (416) 922-1937
SCO Canada, Inc. (formerly HCR) 130 Bloor St. W., Toronto, Ontario, Canada
{utzoo, utcsri, uunet}!scocan!tom or tom@sco.com

mat@mole-end.UUCP (Mark A Terribile) (01/02/91)

In article <1990Dec20.204737.25444@sco.COM>, tom@sco.COM (Tom Kelly) writes:

> 		   ...  I derive from that base class, inheriting new
> and delete.  I expect the new and delete operators to be called with
> the appropriate size of the derived objects.

So far, so good.
 
> It works fine for operator new().  However, the second argument to 
> operator delete() is always the same, and reflects the size
> of the base class.

> According to E&S (ARM), p. 283:
 
> 	...  The size passed ...  will be correct either if the
> 	type of the pointer argument to the delete operator is
> 	the exact type of the object (and not, for example, just the
> 	type of base class) or if the type is that of a base class
> 	with a virtual destructor.

> Since all my deletes are using the exact type of the object, I expect
> delete to get the right size.
 
> Am I mis-interpreting the ARM and doing something wrong, or is this
> a bug in cfront?  If the code ifdef'd with FIX is compiled in, then
> the program works and gets the expected answer.

I think you have a bug.  If it is any consolation, you probably should
use the virtual destructor anyway unless you are very badly cramped for
space.  It's just plain safer.

My own view is that C++ ought to disable SOMETHING when inherited destructors
are not virtual.  The derived* => base* conversion might be a candidate; so
might the availability of  operator delete in derived classes.  There is a
serious weakness in C++ in this area, I think.
-- 

 (This man's opinions are his own.)
 From mole-end				Mark Terribile