[comp.lang.c++] Object pointers, and destructors

cs162sbj@uape_5.ucsd.edu (....What Is?....) (05/31/91)

I've become a pretty good beginner at C++ & am ready to move on to
intermediate.  Before I do, I need some clarifications on C++ that I
haven't been able to find in the books I've read.  They might be dumb
questions, or may have been thoroughly discussed, but here goes
anyways.

[1] Why aren't pointers hidden/protected/controlled/etc. the way
	class objects are?  I was doing a symbol table for a class project
	which kept reference counts on all the objects & the objects that
	they pointed to, and a single pointer assignment in the "main
	program" from a pointer returned by a member function to a new
	pointer is enough to throw the reference count off.  I want to be
	able to control pointer assignments the way I can control object
	assignments, but I haven't been able to overload operators using
	pointers to objects, just objects.  How is what I want to do
	accomplished cleanly?

[2] Why doesn't delete() automatically set the original pointer to
	NULL?  I can't do it from within my destructor, and I can find no
	reason to leave it pointing to freed memory.

Steven Boswell
whatis@ucsd.edu

robert@kohlrabi.tcs.com (Robert Blumen) (06/01/91)

In article <19944@sdcc6.ucsd.edu>, cs162sbj@uape_5.ucsd.edu (....What
Is?....) writes:
|> [1]
|>	  I want to be
|> 	able to control pointer assignments the way I can control object
|> 	assignments, but I haven't been able to overload operators using
|> 	pointers to objects, just objects.  How is what I want to do
|> 	accomplished cleanly?

Perhaps you can do what you want by overload the per-class operator new,
operator delete, and operator &.  You can also define pointer objects that
have the desired semantics (most generically done using templates) and
use the pointer objects rather than regular pointers for the classes that
need ref counts.

|> [2] Why doesn't delete() automatically set the original pointer to
|> 	NULL?  I can't do it from within my destructor, and I can find no
|> 	reason to leave it pointing to freed memory.
|> 
You could do this yourself by writing your own ::operator delete and linking 
it into your code.  I can't say just why it doesn't do this, since not
doing so means that the post-delete pointer value is certainly invalid.  It
is consistent with the C++ philosophy "it doesn't work this way by default
but you can do it yourself"

-----------------------------------------------------------------------------
Robert Blumen                          | rblumen@tcs.com
Senior Software Engineer               | 2121 Allston Way, Berkeley, CA 94704
Teknekron Communications Systems, Inc. | (415) 649-3759

warsaw@nlm.nih.gov (Barry A. Warsaw) (06/05/91)

>>>>> "Robert" == Robert Blumen <robert@kohlrabi.tcs.com> writes:

	Robert> You could do this yourself by writing your own ::operator
	Robert> delete and linking it into your code.

Are you sure?  Doesn't ::operator delete *require* an argument type of
void* and forbid void*&, which would be necessary if setting the
pointer to zero after deleting would have any effect outside of the
operator?  I don't have the ARM around, but I know my 2.0 cfront barfs
on:

void ::operator delete( void*& ptr ) { ... };

CC  foo.cc:
"foo.cc", line 7: error:  operator delete()'s 1st argument must be a void*

But perhaps I'm missing something?

	Robert> I can't say just why it doesn't do this, since not doing
	Robert> so means that the post-delete pointer value is certainly
	Robert> invalid.

When I asked this question 6-8 months ago, people correctly pointed
out that just setting the pointer to zero won't solve all your
problems, for example in cases where two pointers are referencing the
same object, you delete the first pointer, it gets set to zero, but
then you accidently dereference the second pointer.  How are you going
to set all pointers referencing some chunk of memory to zero?  Not in
any built-in way, that for sure.  And it *does* cost enough
performance-wise to warrant not being built into the language.

	Robert> It is consistent with the C++ philosophy "it doesn't work
	Robert> this way by default but you can do it yourself"

Hmm. I for one would've liked to see ::operator delete take a void*&
so you *could* do this if you wanted (which, right now, you can't).
Still after listening to what more experienced programmers were
saying, and getting some C++ time under my belt, I think you really
need to take a much more careful approach when throwing pointers to
objects around. Using ::operator delete could lull one into a false
sense of security :-).

-Barry

"When in doubt, cout."

jamshid@ut-emx.uucp (Jamshid Afshar) (06/10/91)

In article <WARSAW.91Jun5120801@warsaw.nlm.nih.gov> warsaw@nlm.nih.gov writes:

<<I removed an attempt at creating an operator delete() which sets
  pointer to 0.>>

<<I also removed an example of how aliasing can still cause a reference to
  freed memory even if delete sets the pointer to 0 .>>

>	Robert> It is consistent with the C++ philosophy "it doesn't work
>	Robert> this way by default but you can do it yourself"
>
>Hmm. I for one would've liked to see ::operator delete take a void*&
>so you *could* do this if you wanted (which, right now, you can't).
>Still after listening to what more experienced programmers were
>saying, and getting some C++ time under my belt, I think you really
>need to take a much more careful approach when throwing pointers to
>objects around. Using ::operator delete could lull one into a false
>sense of security :-).
>
>-Barry
>
>"When in doubt, cout."

Page 63 of the ARM mentions that modifying the pointer after a delete
would be useful for debugging.  It would have to be something the
compiler does, as there is no way for the programmer to do it by
overloading operator delete.  operator delete cannot take a reference
to a void* because while the _value_ of any object pointer can always
be converted to the _value_ of a void*, the actualy object pointer is
not a void* (e.g.  you can't pass an int** to a void**).  This is an
important fact that helps in understanding why you can't pass the
'address of a pointer to a Derived' to a function expecting the
'address of a pointer to a Base' (a c.l.c++ faq-- has anyone taken up
the challenge of maintaining a FAQ list?).

I do believe that setting the pointer to 0 (or some "bad" address)
after a delete is well worth the effort as a significant number of
bugs are caused by referencing objects after they are deleted.  This
is a very nasty bug because in alot of C++ implementations, using
freed memory will _not_ cause your program to crash (especially during
testing :-).  I always set the pointer to 0 after a delete in my code
and it has caught alot of bugs (one particularly bad one was a
compiler bug causing the destructor to be called twice).

Of course there is no way to keep another pointer from referencing the
freed memory, but the simple case is common enough and easy enough to
prevent without a significant performance penalty (I was relieved to
see a poster unanimously flamed in comp.lang.c for asserting that
testing p!=0 in free(p) is a significant performance penalty "when you
have 1000 free's").

I definitely agree that you have to be very careful with pointers in
C/C++.  Since I've been using C++ I have tried to restrict my use of
pointers to private class member variables and rarely even use them
there because of references or my complete disregard for efficiency
:).  "Smart" pointers, objects that behave like pointers but keep a
reference count and can do other checking, seem like they would be
helpful, but I've never actually created a smart pointer class for any
of my classes.  Does anyone have a simple example they can post?  It
seems like templates would help in creating smart pointers.  As a
matter of fact, it seems like templates would help in alot of
non-obvious (at least to me) ways.  For example, someone posted a
while back a simple template which would "automaticly" create
operator!=() if your class defined a operator==()).

Jamshid Afshar
jamshid@emx.utexas.edu
"Keep sigs short."

2195bm@gmuvax.gmu.edu (06/10/91)

In article <50253@ut-emx.uucp>, jamshid@ut-emx.uucp (Jamshid Afshar) writes:
> 'address of a pointer to a Base' (a c.l.c++ faq-- has anyone taken up

Hmmm: faq--
Does this mean Read the whole FAQ list, then delete the least-
frequently asked question?

// john porter