Around 1 o'clock on Dec 2, MenTaLguY wrote:
The only general solution I've found so far is to create
synthetic
"anchor" objects which are attached to a root and contain a refcount and
a pointer to the managed memory. Usually the interfaces provided by the
closures or whatever are sufficient to manage a refcount.
That's what I tried to suggest, but your wording is quite a bit clearer...
Hmm. One of the reasons I adopted a garbage collector was to
facilitate
writing in a functional style which would unfortunately be susceptible
to this sort of problem.
Except for loops (and recursion), the overhead is all constant. For
example, Nickle does lots of stuff like:
av = Reduce (NewInteger (sign,
NaturalRsl (IntegerMag(IntegerRep.promote (av,0)),
b)));
which does leave four extra values referenced temporarily, but those are
dereferenced on exit from this function. When necessary, you can also
just explicitly bracket sequences of code with ENTER()/EXIT() macros;
obviously a pain, but at least you can manage recursion and iteration
without running out of memory.
In this specific example, though, I don't believe the macros are
necessary. I would expect this to work:
void bar() {
MemStackFrame frame;
operate(a(), b(), c());
}
Yes, that's clearly the way to manage this in C++.
At least it's more portable. As you probably know, at least on
paper
memset() isn't a portable way to initialize pointers.
When I find a modern machine for which memset doesn't work, I'll alert the
media, but I agree it's nicer to just not assume things like this. The
real reason for the change was to avoid ripping across large chunks of ram
for no good reason.
In Inkscape I actually fill memory allocated for some classes with
garbage before their constructor is called. It's helped shake out some
subtle bugs that were previously flying below the radar because zero was
close to a sensible value (and pages claimed from the OS are often
initally zero-filled).
This was my basic reason -- it provided a clean invarient (all allocated
memory is zero) which prevents surprises when you suddenly start re-using
previously allocated memory instead of new memory.
Of course, I'd rather have the Nickle behaviour where using uninitialized
values cause an exception to be raised, but C isn't that helpful.
Er, forgive my curmudgeonly ranting. ^^; I still wonder whether
there
might be another good conservative solution to the
initialization/allocation ordering problem...
Yes, that would be nice. The real problem was across the transition where
the code implicitly assumed that data were initialized to zero (and, of
course, where NULL was represented by zero bits). New code is written in
a more stylized fashion:
foo = ALLOCATE (&type, sizeof (type));
foo->value1 = 0;
foo->pointer1 = NULL;
... code using foo
Which, as you say, provides some level of self-documentation.
-keith