Re: Record type flushing

From: Rob Kennedy (me3_at_privacy.net)
Date: 04/08/04


Date: Thu, 08 Apr 2004 12:44:12 -0500

AlanGLLoyd wrote:
> I'm just trying to get my mind round the use of "reference-counted
> fields" (AIUI these are essentially from interfaces / AX / COM) and
> storage in records. I would associate storage in records with
> isolated values which do not depend on items external to the records.
> Or are "reference counted fields" in records just a more complex use
> of records ? Could you explain a little.

Reference-counted fields include strings, interfaces, dynamic arrays,
and any structured types -- arrays and records -- that contain
reference-counted fields. (Yes, it's a recursive definition.) I prefer
the terms "managed" or "compiler-managed" instead of "reference-counted"
since both AnsiStrings and WideStrings need special handling, but
WideStrings aren't reference-counted. All the above types have special
code inserted by the compiler when you use them.

> What could be the effect of not using New() for allocating memory for
> records ?

If you use GetMem to allocate your record, then memory contents will be
random. If you try to assign a new value to a string field in that
record, the compiler will insert its normal string-handling code, which
decreases the reference count on a non-empty string before assigning a
new value. The record doesn't really contain any valid strings (since it
was only just allocated), but the compiler doesn't know that. The random
value that GetMem left in the string field looks like a valid string
reference, so the compiler's code tries to release that reference before
assigning the new one. That quickly leads to an access violation.

The Initialize procedure can be used to solve that problem. Initialize
will go through each of the record's fields recursively, setting any
managed fields to their "empty" values -- the values that ensure that
nothing tries to delete them when assigning a new value -- *without*
trying to interpret the previous values as valid references. String
fields will be set to '', and interfaces will be set to nil. However,
any unmanaged fields should retain their initial "random" values. In
effect, it's the same as if you had declared the record on the stack.
The values are initialized the same way as normal local variables.

The New procedure is conceptually equivalent a call to GetMem
immediately followed by a call to Initialize. Likewise, Dispose is the
same as Finalize + FreeMem. The Finalize procedure destroys any managed
fields in the record, but it does not necessarily set those fields'
values to their "empty" states. The assumption is that the next thing
you're going to do is free the memory anyway, so there's no point in
setting values that will never be read again.

The AllocMem function is the same as a call to GetMem followed by
FillChar(0). In practice, it ends up yielding even better results than
New since all the fields in the record are zeroed, not just the managed
ones. However, there is nothing formally defining the managed fields'
empty values as being the same as zeroed values. There is nothing
requiring that an empty string or array must be represented internally
by a nil pointer. That's just an implementation detail. Therefore, to be
on the safe side, I recommend calling Initialize, even on variables
allocated with AllocMem.

Since New and Dispose are available, there typically isn't any need for
Initialize and Finalize. Where they come in handly is on memory
allocated from something other than Delphi's built-in memory-management
functions. If you're using the shell's memory manager, or calling the
heap API functions, then Initialize and Finalize should also be there.

-- 
Rob


Relevant Pages

  • Re: Lets make it backwards compatible :D
    ... > Incorrect use of Initialize. ... it is a string. ... The pointer storage would point to the null terminator. ... Storage now holds a string reference. ...
    (alt.comp.lang.borland-delphi)
  • Re: Lets make it backwards compatible :D
    ... > Man the string type gives me the shit. ... Incorrect use of Initialize. ... However, since the value of Storage is nil, Initialize ... Storage now holds a string reference. ...
    (alt.comp.lang.borland-delphi)
  • Re: Complex Specified Information - Pitman Formula
    ... Therefore a significant match between a reference and a test ... string is good evidence of non-random production. ... and there are no finite algorithms to compute their digits. ... probabilities of the different symbols the information source can produce. ...
    (talk.origins)
  • Re: String Reference Type
    ... All unary and binary operators have predefined implementations that are ... Therefore its always allocated in the heap and a variable of string ... As with all classes in this case y and x both reference the same String ... language depandant matter as below. ...
    (microsoft.public.dotnet.framework.aspnet)
  • Re: Abstract class variables question
    ... But as I think you've seen elsewhere in this thread, a value type can exist inside a class and in that case the value type is stored in the heap with the rest of the class instance. ... But as far as the "faster" goes, yes...to some extent value types have less overhead than reference types, and so can perform better in certain cases. ... Well, that would be true for a string object too, if there was any way to actually change a string. ... Seriously though, it is practically always the case that when you are writing an assignment to a reference, you're replacing the reference held by the variable. ...
    (microsoft.public.dotnet.languages.csharp)

Loading