Re: The D Programming Language
PeteK wrote:
James Kanze wrote:
PeteK wrote:
You can easily get rid of dangling pointers in C++ and turn them into
zombies instead by simply using a bolt-on garbage collector. The
language doesn't stop you doing that.
I'm not sure I understand your point. For the purposes of this
discussion, there are two fundamental types of data, those with
a determinate lifetime, and those with an indeterminate lifetime
(from the design point of view). For dynamically allocated
objects with an indeterminate lifetime, current C++ requires you
to explicitly use a delete expression, and make the lifetime
determinate (and risk dangling pointers). Java just does the
right thing. For dynamically allocated objects with a
determinate lifetime, C++ has a standard "name" for the function
terminating the objects lifetime, the destructor. It's a little
wierd, in that it doesn't have the normal function call syntax,
but big deal. Java lacks anything standard, but the convention
seems to be established to use the name "dispose()" (although
some of the standard classes use this name for other things).
In the end, it comes out to the same thing. Or almost---if you
want to, you can set state in the dispose() function in Java to
ensure that later use is detected. Immediately. To get this in
C++, you need something like Purify, and the runtime overhead is
high enough that you can't use it in production code. So Java
offers a safer solution.
But in C++ you can
a. Use a garbage collector
b. Add a dispose function that sets the state, then calls delete (so
you can run it non-GC)
Now you've got exactly the same situation as in Java. C++ doesn't
prevent you from doing this.
But you'll have to admit that it's a very strange way. In C++,
we have the standard "name", which is that of the destructor;
I'd put such verifications in the destructor.
But I agree that the problem isn't present (except perhaps for
some special cases) if you're using garbage collection with C++.
However in Java you are stuck
with the GC system and there's no way to automate the detection of
zombies (big assumption here by someone who's never used it).
You can detect them just as easily as in C++. The big
difference is that you don't need external instrumentation that
makes the detection too slow to be used in production code.
You missed the word "automate". You need to add dispose functions (and
the associated checks) by hand. Using purify is somewhat simpler.
Using Purify isn't all that simple, either:-). But the bigger
issue is that the Purify checks aren't there when you need them,
in production code.
In principle it should be possible to pick up all potential
zombies/dangling pointers in C++ by using a sufficiently clever
debugging allocator.
I think some systems do this. The trick is to not make the
memory available for re-allocation as long as there is a pointer
to it still in existance, mark it as freed somehow, and then
instrument every single pointer dereference to check for the
mark. (It still misses dangling pointers to on stack objects,
of course.) The problem is that it has unacceptable runtime
cost; ...
Unacceptable for production use, probably. Unacceptable for debugging
etc. unlikely. Purify really slows things down, but on the odd
occasion you need it it's really worth it.
Certainly. I very much like Purify. But I do like to have
important sanity checks in production code, as well.
Note that the issue only affects a few classes. Most objects do
not have (or at least don't need) a deterministic lifetime.
Also, given that people don't seem to think that GC slows things down
too much, I can't (off the top of my head) see why freed memory blocks
can't simply be added to a list then put back into play in a big chunk.
At this stage a GC-like scan could be run to see if any pointers to
the deleted memory remain (with optional invalidation of the pointers
to cause a PE on dereference).
That's certainly an option. I think that the Boehm collector
can be used more or less in this way; if not, it certainly
wouldn't be too difficult to modify it so that it could. About
the only thing you couldn't do with it would be to modify the
pointer values, since at present (and probably for ever), the
collector cannot know with 100% certainty what is a pointer, and
what isn't.
But at that point, why bother with the extra work. I don't
understand your point. If you're running a garbage collector,
why not use it generally. Take advantage of it, and save
yourself some work.
...the standard C++ model requires that all objects have
explicit lifetimes, even when the design doesn't require it, so
you have to check every single pointer dereference, and not just
those where the object by design has a determinate lifetime.
And if you think of things like the implementation of a string
class, you'll realize that there are a lot of objects which,
like the char array in a string, don't need explicit lifetime.
The thing is that all objects have a logical lifetime.
Nonsense. What's the logical lifetime of the char[] which
contains the characters in a string? In fact, very few objects
have a logical lifetime.
Accessing them
after their logical life is over is an error. Java choses to define
this as "not an error" (although this is probably more to do with Java
having GC). While it might appear that a string's char array doesn't
require a specific lifetime, if you've somehow acquired a pointer into
it then the array is kept alive long after the string is dead.
What does that mean, after the string is dead? The string is
never "dead", in any real sense of the word. At some point, it
ceases to be accessible, but it's not logically dead.
If you
use this pointer to access the char array then this is logically wrong,
but you have absolutely no way of detecting it.
Why is it logically wrong?
The essential thing in being able to detect the problem, of
course, is not allowing memory to be reused as long as there is
still an existing pointer to it. Garbage collection, in sum.
(The Boehm collector is often used in this way, as a leak
detector, and, with additional instrumentation in user code, to
detect dangling pointers.)
No, there are things you can't detect. If you have an array of ints
that can legitimately take all integer values, how can you tell that
you're pointing at an array that will no longer be updated?
But that's the same situation as in C++, or in every other
language. You expect values to be updated every second, say.
For some reason (program error, etc.), the update doesn't occur.
No language feature that I know will protect against that sort
of thing, and no external tool will detect it.
The problem isn't that the object is dead. The problem is that
two different parts of the program disagree as to what is
supposed to be happening with it.
Admittedly this doesn't stop you assigning duff
values to pointers, but that's the price you have to pay for using a
system-level language.
There are several issues at stake. The fact that you can have
an uninitialized pointer, with undefined contents, can hardly be
considered a feature.
I didn't say it was uninitialised, and even a default initialisation to
NULL might be no help. After all, address zero was a perfectly valid
address under DOS*. A system level language must allow the programmer
to give a pointer any value that could possibly be valid on the target
system. The problem is that very few programs require that level of
freedom, but it's a price we have to pay.
{*Actually I think making NULL equivalent to zero was a mistake. It
should be a system-defined value.}
NULL is just a macro. A null pointer does contain a
system-defined value. It's not required to be zero, and there
have been systems where it wasn't zero.
What is required is that an integral constant expression which
evaluates to 0 will convert implicitly to whatever the null
pointer value is. A rather peculiar rule, to put it mildly,
since the rules for converting an int to a pointer depend on
whether the int is a constant or not, and if it is a constant,
the value of that constant.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]