[comp.lang.c++] Change to delete is in order

shap@delrey.sgi.com (Jonathan Shapiro) (03/13/90)

I believe that a small change to the definition of the delete operator
is worth considering.  The change would have no effect on correct
programs, but would help find incorrect programs in some circumstances.

	delete should be defined to zero the pointer it is handed
	after freeing the associated store.

Reasons:

1. Unlike C, C++ does not guarantee that the object is live until the
   next call to new.

2. In the absence of setting the pointer to zero, accesses to data
   items that erroneously follow the delete cannot be caught even when
   the hardware traps page-zero references, and compilers have not yet
   arrived that understand about this.

3. If the code is correct, dead code elimination in the compiler can
   generally be relied on to eliminate the zero set, so the run-time cost
   should be nil.

4. I can't think of a correct code sequence it would break.

Of course, compilers should be taught to understand about use after
clobber, but that's a bit harder, and I don't see how this tweak to
the language spec can hurt.

Jonathan Shapiro
Silicon Graphics, Inc.

rfg@ics.uci.edu (Ronald Guilmette) (03/13/90)

In article <5136@odin.SGI.COM> shap@delrey.sgi.com (Jonathan Shapiro) writes:
>I believe that a small change to the definition of the delete operator
>is worth considering.  The change would have no effect on correct
>programs, but would help find incorrect programs in some circumstances.
>
>	delete should be defined to zero the pointer it is handed
>	after freeing the associated store.

That would be a swell idea, except that I don't believe that the value
in a delete statement is required to be an lvalue.  What should the compiler
do if the value is *not* an lvalue?  Punt?

// Ron Guilmette (rfg@ics.uci.edu)
// C++ Entomologist
// Motto:  If it sticks, force it.  If it breaks, it needed replacing anyway.

sakkinen@tukki.jyu.fi (Markku Sakkinen) (03/14/90)

In article <25FC0210.26173@paris.ics.uci.edu> rfg@ics.uci.edu (Ronald Guilmette) writes:
>In article <5136@odin.SGI.COM> shap@delrey.sgi.com (Jonathan Shapiro) writes:
>>I believe that a small change to the definition of the delete operator
>>is worth considering.  The change would have no effect on correct
>>programs, but would help find incorrect programs in some circumstances.
>>
>>	delete should be defined to zero the pointer it is handed
>>	after freeing the associated store.
>
>That would be a swell idea, except that I don't believe that the value
>in a delete statement is required to be an lvalue.  What should the compiler
>do if the value is *not* an lvalue?  Punt?

Right: If the delete operator is redefined for a class, then according
to the C++ 2.0 Reference Manual it will be like
   void operator delete (void*)
(possibly with a second argument). Thus it only gets a _copy_ of the
pointer value.

Shapiro's proposal is nevertheless sensible, and would make 'new' and
'delete' more symmetric. The zeroing could be done _if_ the operand
is an lvalue. For a redefined delete operator, this could be done
_before_ it is actually invoked, but after the destructor (if any)
is invoked.

Of course one can keep many pointers to a dynamic object,
but in the majority of cases in "typical" code there is probably
only one pointer to each object, and so zeroing it automatically
would help a lot, e.g. prevent trivial errors.

Markku Sakkinen
Department of Computer Science
University of Jyvaskyla (a's with umlauts)
Seminaarinkatu 15
SF-40100 Jyvaskyla (umlauts again)
Finland
          SAKKINEN@FINJYU.bitnet (alternative network address)

shap@delrey.sgi.com (Jonathan Shapiro) (03/15/90)

In article <3743@tukki.jyu.fi> sakkinen@jytko.jyu.fi (Markku Sakkinen) writes:
>
>Shapiro's proposal is nevertheless sensible, and would make 'new' and
>'delete' more symmetric.  The zeroing could be done _if_ the operand
>is an lvalue. For a redefined delete operator, this could be done
>_before_ it is actually invoked, but after the destructor (if any)
>is invoked.

All I wanted was a definition that helped debugging on many systems if
it wasn't incorrect.  Enough people have pointed out that rvalues make
it a problem that I am forced to conclude that it isn't correct and
shouldn't be part of the language definition.

It might still be worth an implementation note to encourage compiler
authors to generate pre-optimized code that zeroes the pointer iff it
is an lvalue in the interest of debugging.

Jon Shapiro
Silicon Graphics

keith@csli.Stanford.EDU (Keith Nishihara) (03/15/90)

Consistency is very important.  A language variant which sometimes nulls
the argument to delete, and sometimes not (according to whether the
argument is an lvalue), and which never zeros additional pointers to
deleted objects invites errors due to misunderstanding and misuse.

Bad idea!

Neil/.		Neil%teleos.com@ai.sri.com

jeffa@hpmwtd.HP.COM (Jeff Aguilera) (03/16/90)

>
>	delete should be defined to zero the pointer it is handed
>	after freeing the associated store.
>

During program testing and development, a custom allocator is
often worthwhile.

I use a moderately piggish allocator that remembers the caller
(by walking the stack frame!!) so that memory leaks can be
tracked down.  The deallocator checks pointer validity, off
by-one errors, and zeroes the allocated store on delete.
Erroneous access to deleted pointers is normally caught
right away.

Since your problem is effectively solved using existing language 
features, may I remind you of your own arrogance: "This is a 
great example of why language design should be left to people
who know what they're doing."  You forgot your smiley :-)
-----
jeffa

sharam@munnari.oz.au (Sharam Hekmatpour) (03/16/90)

From article <5136@odin.SGI.COM>, by shap@delrey.sgi.com (Jonathan Shapiro):

> 	delete should be defined to zero the pointer it is handed
> 	after freeing the associated store.

I agree with you. A few people have pointed out that this causes problems
when the operand of delete is not an lvalue. They are WRONG. Let me
explain why...

The case that the operand is *not* an lvalue can be handled by, for
example, ensuring that a *copy* of the pointer is zeroed instead
(as if no zeroing has taken place). This is perfectly safe.

Using references, implementing this in C++ is very easy:

	inline void
	zelete (void*& ptr)	// Zero after dELETE
	{
		delete ptr;
		ptr = 0;
	}

Now suppose p and q+10 point to valid blocks created by new:

	zelete(p);	// deletes and zeros p
	zelete(q+10);	// deletes but does not zero q+10

In the latter case, because the formal argument is a reference, the
actual argument is treated as a value; hence ptr receives a *copy* of
q+10 and zeros that! So non-lvalues are treated properly.

Aside, it is a shame that this cannot be achieved by globally overloading
delete, since we will end up with infinite recursion. Defining it as a
function having a different name (as I've done here) is just about the
neatest way I can think of right now.

Regards,

Sharam Hekmatpour

ark@alice.UUCP (Andrew Koenig) (03/17/90)

In article <5136@odin.SGI.COM>, shap@delrey.sgi.com (Jonathan Shapiro) writes:

> I believe that a small change to the definition of the delete operator
> is worth considering.  The change would have no effect on correct
> programs, but would help find incorrect programs in some circumstances.

> 	delete should be defined to zero the pointer it is handed
> 	after freeing the associated store.

But the pointer might not be an lvalue!

In any event, if you look at the latest C++ reference manual,
you will find that the implementation is permitted (but not obliged)
to zero the pointer that is the subject of `delete.'

It is not obliged to do so in case some people don't want to
live with the small amount of additional overhead implied.
-- 
				--Andrew Koenig
				  ark@europa.att.com

rfg@ics.uci.edu (Ronald Guilmette) (03/18/90)

In article <5263@odin.SGI.COM> shap@delrey.sgi.com (Jonathan Shapiro) writes:
>In article <3743@tukki.jyu.fi> sakkinen@jytko.jyu.fi (Markku Sakkinen) writes:
>>
>>Shapiro's proposal is nevertheless sensible, and would make 'new' and
>>'delete' more symmetric.  The zeroing could be done _if_ the operand
>>is an lvalue. For a redefined delete operator, this could be done
>>_before_ it is actually invoked, but after the destructor (if any)
>>is invoked.
>
>All I wanted was a definition that helped debugging on many systems if
>it wasn't incorrect.  Enough people have pointed out that rvalues make
>it a problem that I am forced to conclude that it isn't correct and
>shouldn't be part of the language definition.
>
>It might still be worth an implementation note to encourage compiler
>authors to generate pre-optimized code that zeroes the pointer iff it
>is an lvalue in the interest of debugging.

Now I think that you are on to a very good idea here!

It would certainly be nice if the language definition were to say that:
"In cases where the expression given in a delete statement is an lvalue,
the value of that lvalue after the execution of the delete statement is
undefined."

A rule like that would allow (but not require) the zeroing of lvalue
pointers given in delete statements.  Implementors could then choose
if they wanted to do the zeroing for the sake of slightly better
debugability.


// Ron Guilmette (rfg@ics.uci.edu)
// C++ Entomologist
// Motto:  If it sticks, force it.  If it breaks, it needed replacing anyway.

psrc@pegasus.ATT.COM (Paul S. R. Chisholm) (03/19/90)

<Krasny Oktyabr:  "The torpedo has acquisition!"  That's the good news?>

In article <5263@odin.SGI.COM> shap@delrey.sgi.com (Jonathan Shapiro)
suggests that "delete p" should set the value of p to a null pointer
after the memory it points at is free.  Later posters suggest that the
pointer may not be an lvalue.  I haven't seen anyone suggest a decent
example where a non-lvalue *should* be passed to delete, and I have a
strong gut feeling that such an expression should probably generate a
warning!  But anyway, if it's an lvalue, yes, I agree, implementors
should be free to zero out the pointer.  (Or not, if the application is
*so* time critical that the assignment might slow things down.  We all
know how expensive assignment is as compared to memory deallocation,
right?-)  Leaving the value alone may also help debugging.

In article <260349F1.24972@paris.ics.uci.edu>, rfg@ics.uci.edu (Ronald
Guilmette) agrees, writing:
> It would certainly be nice if the language definition were to say that:
> "In cases where the expression given in a delete statement is an lvalue,
> the value of that lvalue after the execution of the delete statement is
> undefined."

Well, open your ugly red book ("UNIX(R) System V AT&T C++ Language
System, Release 2.0, Product Reference Manual", select code 307-146) to
page 20, and repeat after me:  "if the expression denoting the object
in a delete expression is a modifiable lvalue its value is undefined
after the deletion."

Well, it's good to know Dr. Stroustrup agrees with us. . . .-)

> // Ron Guilmette (rfg@ics.uci.edu)

Paul S. R. Chisholm, AT&T Bell Laboratories
att!pegasus!psrc, psrc@pegasus.att.com, AT&T Mail !psrchisholm
I'm not speaking for the company, I'm just speaking my mind.
UNIX(R) is a registered trademark of AT&T.

P.S.:  How does one have an unmodifiable lvalue?  By using the const
keyword, of course.  I'd like a warning there, too.