Board index » delphi » Destructor Question

Destructor Question

Don't Delphi objects have destructors?
The reason I ask is I see lots of

x := TMemoryStream.Create;
try
...
finally
    x.Free;
end;

Why doesn't the TMemoryStream class (in this example, there are lots of
other classes where I see this) have a destructor that calls Free on itself?
Note I am new to Delphi (about 1 week of coding in it). The reason this
particular question came up was I located a decent socket lib that did not
implement all the stream functions for loading/saving to the stream in the
socket and I added code to complete that.

Thanks
Jeff

 

Re:Destructor Question


A destructor is simply a subroutine that is called, if it exists, before
the memory associated with the object is freed.  It's a cleanup-routine,
whose job is to undo whatever a constructor (which is an
initialization-routine...) did.

The process of allocating an object {see "classes.pas"} is:
        ->  AllocMem the object memory (which sets it all to zero)
        ->  Set up various pointers and administrivia
        ->  Call the constructor if any

And destroy:
        ->  If there's a destructor, call it
        ->  FreeMem the memory.

The "free" logic =calls= the destructor .. not the other way around.  If
the destructor were to try to free the object itself, endless recursion
would result.

One other very(!) important thing to know {btw:  this issue cost me
$10,000 *real* dollars!}:

When your destructor Frees an object, the VERY NEXT STATEMENT should be
to set that pointer to "nil."  Free, for good reasons not worth
discussing here (again...) does NOT do that.  It's quite possible that
the destructor of the next object you free (in your destructor...) might
somehow refer to your object ... and to the pointer, now STALE because
you just freed the object [unless you set it to "nil" as I recommend].

A double-free is a GREAT way to >completely< trash Windows.  And I mean,
"Windows completely vanishes and you have a DOS-prompt or a blank
screen!"  So be _extremely sure that, when you "free" something, the
VERY NEXT STATEMENT wipes away all references to it!

Quote
Jeff Lindholm wrote:

> Don't Delphi objects have destructors?
> The reason I ask is I see lots of

> x := TMemoryStream.Create;
> try
> ...
> finally
>     x.Free;
> end;

> Why doesn't the TMemoryStream class (in this example, there are lots of
> other classes where I see this) have a destructor that calls Free on itself?
> Note I am new to Delphi (about 1 week of coding in it). The reason this
> particular question came up was I located a decent socket lib that did not
> implement all the stream functions for loading/saving to the stream in the
> socket and I added code to complete that.

----------------------------------------------------------------
Sundial Services :: Scottsdale, AZ (USA) :: (480) 946-8259
mailto:i...@sundialservices.com  (PGP public key available.)

- Show quoted text -

Quote
> Fast(!), automatic table-repair with two clicks of the mouse!
> ChimneySweep(R):  Release 4.0 is here!!
> http://www.sundialservices.com/products/chimneysweep

Re:Destructor Question


Quote
"Jeff Lindholm" <jeff_n...@lindholm.org> wrote in message

news:HmsR7.129$vX6.63667@news1.iquest.net...

Quote
> Don't Delphi objects have destructors?

Yes. The default destructor is called Destroy. Its a virtual method declared
in tObject. Free is also declared in tObject. It calls Destroy. The virtue
of Free is that it will not raise an error if it is called on a nil
reference, i.e.

obj := nil;
obj.Free;

will not raise an error. In D5 and above there is also the FreeAndNil
procedure which sets its actual parameter to nil and destroys any object
instance.

Typically when subclassing the derived class only needs to override Destroy
if it has directly allocated resources that need to be released. A typical
override has the form

begin
// release resources
inherited Destroy;
end;

The call to the inherited destructor will take care of releasing any
resources allocated by ancestors. And, IIRC, tObject.Destroy takes care of
releasing the actual space allocated to the instance.

Re:Destructor Question


Quote
Jeff Lindholm wrote in message ...
>Don't Delphi objects have destructors?
>The reason I ask is I see lots of

>x := TMemoryStream.Create;
>try
>...
>finally
>    x.Free;
>end;

>Why doesn't the TMemoryStream class (in this example, there are lots of
>other classes where I see this) have a destructor that calls Free on

itself?

Perhaps you should read the help files for a bit, maybe even
a book, before you come out with The Definitive Statement About
How Delphi Should Work. Especially if that statement shows a
serious lack of understanding about how Delphi actually does
work.

Quote
>Note I am new to Delphi (about 1 week of coding in it). [...]

It shows. But you've programmed other languages before, right?
Breaking news: Delphi is not C++.

Delphi objects do have destructors. But they are not automatically
called when a variable goes out of scope, because Delphi objects
are not allocated on the stack. Ever. Smarter people than you
and me combined (well, perhaps I'm easily impressed. But he _does_
write in Dr. Dobb's Journal) seem to misunderstand the consequences
of this.

Free calls an object's destructor under conditions detailed in
the help files. It does NOT do anything else, and it is especially
not involved in deallocating memory. The destructor does this.

Since object destruction is not automatical, and Free has certain
advantages over Destroy (the standard destructor), the code
sequence outlined above is _very_ common. And quite correct.

Groetjes,
Maarten Wiltink

Re:Destructor Question


Well thanks for the information, other than the one person who thinks I was
trying to make "The Definitive Statement About How Delphi Should Work" I
just wanted an answer that I did get. Delphi objects are not created on the
stack. (Note: This is a fine answer and one I understand and even know some
reasonings behind it).

Quote
"Jeff Lindholm" <jeff_n...@lindholm.org> wrote in message

news:HmsR7.129$vX6.63667@news1.iquest.net...
Quote
> Don't Delphi objects have destructors?
> The reason I ask is I see lots of

> x := TMemoryStream.Create;
> try
> ...
> finally
>     x.Free;
> end;

> Why doesn't the TMemoryStream class (in this example, there are lots of
> other classes where I see this) have a destructor that calls Free on
itself?
> Note I am new to Delphi (about 1 week of coding in it). The reason this
> particular question came up was I located a decent socket lib that did not
> implement all the stream functions for loading/saving to the stream in the
> socket and I added code to complete that.

> Thanks
> Jeff

Re:Destructor Question


Wow, well yes I am new and I guess it shows. But all I wanted was an answer
not to be berated for tying to make "The Definitive Statement About How
Delphi Should Work." I in no way implied my way was how it SHOULD work I
just wanted to know why it DIDN'T.

Good luck in that PR job.

Quote
"Maarten Wiltink" <maar...@kittensandcats.net> wrote in message

news:9v5rf8$13r$1@news1.xs4all.nl...
Quote
> Jeff Lindholm wrote in message ...
> >Don't Delphi objects have destructors?
> >The reason I ask is I see lots of

> >x := TMemoryStream.Create;
> >try
> >...
> >finally
> >    x.Free;
> >end;

> >Why doesn't the TMemoryStream class (in this example, there are lots of
> >other classes where I see this) have a destructor that calls Free on
> itself?

> Perhaps you should read the help files for a bit, maybe even
> a book, before you come out with The Definitive Statement About
> How Delphi Should Work. Especially if that statement shows a
> serious lack of understanding about how Delphi actually does
> work.

> >Note I am new to Delphi (about 1 week of coding in it). [...]

> It shows. But you've programmed other languages before, right?
> Breaking news: Delphi is not C++.

> Delphi objects do have destructors. But they are not automatically
> called when a variable goes out of scope, because Delphi objects
> are not allocated on the stack. Ever. Smarter people than you
> and me combined (well, perhaps I'm easily impressed. But he _does_
> write in Dr. Dobb's Journal) seem to misunderstand the consequences
> of this.

> Free calls an object's destructor under conditions detailed in
> the help files. It does NOT do anything else, and it is especially
> not involved in deallocating memory. The destructor does this.

> Since object destruction is not automatical, and Free has certain
> advantages over Destroy (the standard destructor), the code
> sequence outlined above is _very_ common. And quite correct.

> Groetjes,
> Maarten Wiltink

Re:Destructor Question


On Tue, 11 Dec 2001 12:50:27 -0700, Sundial Services

Quote
<info_...@sundialservices.com> wrote:
>A destructor is simply a subroutine that is called, if it exists, before
>the memory associated with the object is freed.  It's a cleanup-routine,
>whose job is to undo whatever a constructor (which is an
>initialization-routine...) did.

>The process of allocating an object {see "classes.pas"} is:
>    ->  AllocMem the object memory (which sets it all to zero)
>    ->  Set up various pointers and administrivia
>    ->  Call the constructor if any

>And destroy:
>    ->  If there's a destructor, call it
>    ->  FreeMem the memory.

>The "free" logic =calls= the destructor .. not the other way around.  If
>the destructor were to try to free the object itself, endless recursion
>would result.

>One other very(!) important thing to know {btw:  this issue cost me
>$10,000 *real* dollars!}:

>When your destructor Frees an object, the VERY NEXT STATEMENT should be
>to set that pointer to "nil."

Again: (i) What cost you the $10,000 is the fact that code somewhere
was _assuming_ that objects <> nil must be valid objects, together
with code elsewhere that didn't set something to nil. It's
not at all hard to write code that does _not_ assume that non-nil
objects are valid - if you do that then there is no reason to set
things to nil.

Either way you have to do it _right_, meaning you have to _stick_
_to_ whatever convention you're using.

(ii) More important: Saying

theObject.Free;
theObject:= nil;

as you seem to be recommending is not fool-proof either; it can
happen that something accesses the object _after_ the Free but
_before_ the ":= nil". (As opposed to if you simply never write
code that assumes that <>nil implies valid - I don't know of a
corresponding problem with that approach.)

If you _do_ want to guarantee safety with this method you need
to set the variable to nil _before_ freeing the object:

Dummy:= theObject;
theObject:= nil;
Dummy.Free;

Quote
> Free, for good reasons not worth
>discussing here (again...) does NOT do that.  It's quite possible that
>the destructor of the next object you free (in your destructor...) might
>somehow refer to your object ... and to the pointer, now STALE because
>you just freed the object [unless you set it to "nil" as I recommend].

>A double-free is a GREAT way to >completely< trash Windows.  And I mean,
>"Windows completely vanishes and you have a DOS-prompt or a blank
>screen!"  So be _extremely sure that, when you "free" something, the
>VERY NEXT STATEMENT wipes away all references to it!

IF one insists on writing code that assumes that <>nil implies
valid then this is very important advice. But that's not the
Only Way. (The way I do things seems much safer to me.)

- Show quoted text -

Quote
>Jeff Lindholm wrote:

>> Don't Delphi objects have destructors?
>> The reason I ask is I see lots of

>> x := TMemoryStream.Create;
>> try
>> ...
>> finally
>>     x.Free;
>> end;

>> Why doesn't the TMemoryStream class (in this example, there are lots of
>> other classes where I see this) have a destructor that calls Free on itself?
>> Note I am new to Delphi (about 1 week of coding in it). The reason this
>> particular question came up was I located a decent socket lib that did not
>> implement all the stream functions for loading/saving to the stream in the
>> socket and I added code to complete that.

>----------------------------------------------------------------
>Sundial Services :: Scottsdale, AZ (USA) :: (480) 946-8259
>mailto:i...@sundialservices.com  (PGP public key available.)
>> Fast(!), automatic table-repair with two clicks of the mouse!
>> ChimneySweep(R):  Release 4.0 is here!!
>> http://www.sundialservices.com/products/chimneysweep

David C. Ullrich

Re:Destructor Question


On Wed, 12 Dec 2001 15:36:01 GMT, ullr...@math.okstate.edu (David C.

Quote
Ullrich) wrote:

<snip>

Quote

>Again: (i) What cost you the $10,000 is the fact that code somewhere
>was _assuming_ that objects <> nil must be valid objects, together
>with code elsewhere that didn't set something to nil. It's
>not at all hard to write code that does _not_ assume that non-nil
>objects are valid - if you do that then there is no reason to set
>things to nil.

How would you do that ?
 A flag ?  One could hardly use a property of the Object.

Realistically it is a pretty dumb thing that simple constructs can
point into the ether - however sorting that out leads to such
complications that we are probably better off living with it.

Sundial's advice is pretty good - there is little point in taking
chances - the upside is trivial and the downside can be seriously
painful.

Re:Destructor Question


Quote
"J French" <je...@iss.u-net.com> wrote in message

news:3c17e1b7.2185862@news.u-

Quote
> >with code elsewhere that didn't set something to nil. It's
> >not at all hard to write code that does _not_ assume that non-nil
> >objects are valid - if you do that then there is no reason to set
> >things to nil.

> How would you do that ?
>  A flag ?  One could hardly use a property of the Object.

Its more a question of designing out the need to test at all. IOW one
designs the code so that there is never a question of the validity of an
object reference.

Quote

> Realistically it is a pretty dumb thing that simple constructs can
> point into the ether - however sorting that out leads to such
> complications that we are probably better off living with it.

That pretty much sums it up.

Quote

> Sundial's advice is pretty good - there is little point in taking
> chances - the upside is trivial and the downside can be seriously
> painful.

Two different design philosophies. IMO either one works so long as the
programmer is careful. The advantage, IMO, of not having to test for nil is
that it is more failsafe. At the worst one gets a memory leak. Which while
not good is much less likely to cause catastrophic failure.

Re:Destructor Question


Quote
David C. Ullrich wrote:
> (ii) More important: Saying

> theObject.Free;
> theObject:= nil;

> as you seem to be recommending is not fool-proof either; it can
> happen that something accesses the object _after_ the Free but
> _before_ the ":= nil". (As opposed to if you simply never write
> code that assumes that <>nil implies valid - I don't know of a
> corresponding problem with that approach.)

The approach is valid =if= the statements are =adjacent= as shown, AND
IF threads are not involved.  {It wouldn't be pretty if two threads
tried to free the same object at the same time.}

Setting the pointer immediately to NIL assures that "Free" will have no
effect, because "Free" of a NIL pointer does nothing.

Note that I _do assume that the destructor of "theObject" will not
somehow refer to us and attempt either to use us or to destroy us.  This
also would result in {*word*193} recursion and double-frees.

The scenario I was encountering was not recursive, but in the sequence:
        a.Free;
        b.Free;
        a := nil;
        b := nil;
... in step #2 the destructor of 'b' referenced us, found 'a', and tried
to free it a second time.  One moment I was in Windows... the next
moment Windows was completely gone and I was staring at my "$10,000 DOS
prompt."

Re:Destructor Question


On Wed, 12 Dec 2001 21:51:00 -0700, Sundial Services

Quote
<info_...@sundialservices.com> wrote:
>David C. Ullrich wrote:
>> (ii) More important: Saying

>> theObject.Free;
>> theObject:= nil;

>> as you seem to be recommending is not fool-proof either; it can
>> happen that something accesses the object _after_ the Free but
>> _before_ the ":= nil". (As opposed to if you simply never write
>> code that assumes that <>nil implies valid - I don't know of a
>> corresponding problem with that approach.)

>The approach is valid =if= the statements are =adjacent= as shown, AND
>IF threads are not involved.

IF.

Quote
> {It wouldn't be pretty if two threads
>tried to free the same object at the same time.}

>Setting the pointer immediately to NIL assures that "Free" will have no
>effect, because "Free" of a NIL pointer does nothing.

I don't know _any_ way that the way that I do it can go wrong.
On the other hand setting objects to nil can induce a false
sense of security. (Just curious: In your opinion _why_ is
it that it took until D5(D4?) for Borland to add FreeAndNil
to the language? People started asking for it as soon as D1
came out. You think the guys at Borland couldn't figure out
how to do it? I tend to suspect that they thought it was a
bad idea, and finally bowed to popular demand. Better
programmers than me share this opinion, btw.)

False sense of security:

var B: TSomeObject;

Somewhere else:

A:= B;
A.Something;
A.Free;
A:= nil;

and now somewhere else:

B.Free;

And you have your double-free kaboom in spite of the
fact that you set your pointer to nil.

So you avoid that by being careful about the scope
of things. But if you're just a little more careful
about scope then there's no need for the := nil
at all, and things are even _safer_.

Quote
>Note that I _do assume that the destructor of "theObject" will not
>somehow refer to us and attempt either to use us or to destroy us.  This
>also would result in {*word*193} recursion and double-frees.

>The scenario I was encountering was not recursive, but in the sequence:
>    a.Free;
>    b.Free;
>    a := nil;
>    b := nil;
>... in step #2 the destructor of 'b' referenced us, found 'a', and tried
>to free it a second time.  One moment I was in Windows... the next
>moment Windows was completely gone and I was staring at my "$10,000 DOS
>prompt."

Well that just seems like bad programming to begin with. Objects
should have clearly-defined owners - A.Destroy should not free
anything except for fields A.FWhatever that it created in the
constructor, and these objects should not be _available_ for code
from outside the object to free. If you have destructors reaching
out into the universe and freeing other objects I'm surprised you
don't have more problems.

Um. When I say "should" above I suppose I should qualify that -
the way I think things should be done is not the only way. But
the way I do these things _is_ very very very safe - what I say
in the previous paragraph is a necessary part of making it safe.
(Necessary if you're doing it "my" way, not that it's _my_ way,
I gleaned it from the docs and the source.)

David C. Ullrich

Re:Destructor Question


On Wed, 12 Dec 2001 23:18:09 GMT, je...@iss.u-net.com (J French)
wrote:

Quote
>On Wed, 12 Dec 2001 15:36:01 GMT, ullr...@math.okstate.edu (David C.
>Ullrich) wrote:

><snip>

>>Again: (i) What cost you the $10,000 is the fact that code somewhere
>>was _assuming_ that objects <> nil must be valid objects, together
>>with code elsewhere that didn't set something to nil. It's
>>not at all hard to write code that does _not_ assume that non-nil
>>objects are valid - if you do that then there is no reason to set
>>things to nil.

>How would you do that ?
> A flag ?  One could hardly use a property of the Object.

No, as Bruce said: program in such a way that you never _need_
to test whether an object is valid.

Quote
>Realistically it is a pretty dumb thing that simple constructs can
>point into the ether - however sorting that out leads to such
>complications that we are probably better off living with it.

Not sure exactly what you're referring to here. But the "fact"
that a Free requires an assignment to nil is not a fact, it's
a symptom of a programming style - there are other ways to do
it where the assignment to nil is simply not necessary.

I _suspect_ that the Other Way is more what the designers had
in mind. Regardless, the Other Way seems definitely safer to me.

Quote
>Sundial's advice is pretty good - there is little point in taking
>chances - the upside is trivial and the downside can be seriously
>painful.

Curiously the people who wrote the VCL seem to have missed Sundial's
advice, and their stuff works pretty well. Look at the source for
the VCL - count how many places the string 'Free' occurs and
how many places the string ':= nil' occurs.

You program in such a way that there is never any question about it:

var O: TSomeObject;
begin
  O:= TSomeObject.Create;
  try
    O.Something;
  finally
    O.Free;
  end;
end;

There's no ":= nil" there and there's also _no_ possibility
that the object will be freed twice. You say there's little
point in taking chances. I agree. Now tell me exactly what
chance I'm taking with code as above. (Answer: None whatever.)

And there's _no_ way that that can go wrong and give a double
free, while there _are_ ways that saying

O.Free;
O:= nil;

can lead to O being freed twice.

When I was an utter beginner my code was littered with
assignments to nil. That's because I was using try-finally
blocks wrong (as well as missing the point to various
other aspects of Delphi.) My programs are _much_ more
robust since I started programming in such a way that the
":= nil" is not necessary. It's not always try-finally,
sometimes it would be initialization-finalization,
or OnCreate-OnDestroy, etc. One way or another you write
in such a way that objects _are_ valid in their _entire_
_scope_.

David C. Ullrich

Re:Destructor Question


Quote
David C. Ullrich wrote in message <3c18ddc2.1112635553@news>...
>On Wed, 12 Dec 2001 21:51:00 -0700, Sundial Services
><info_...@sundialservices.com> wrote:

>>David C. Ullrich wrote:
>>> (ii) More important: Saying

>>> theObject.Free;
>>> theObject:= nil;

>>> as you seem to be recommending is not fool-proof either; it can
>>> happen that something accesses the object _after_ the Free but
>>> _before_ the ":= nil". (As opposed to if you simply never write
>>> code that assumes that <>nil implies valid - I don't know of a
>>> corresponding problem with that approach.)

>>The approach is valid =if= the statements are =adjacent= as shown, AND
>>IF threads are not involved.

>IF.

>> {It wouldn't be pretty if two threads
>>tried to free the same object at the same time.}

>>Setting the pointer immediately to NIL assures that "Free" will have no
>>effect, because "Free" of a NIL pointer does nothing.

IF threads are involved, { A.Free; A:=nil; } isn't safe
because competing threads can both try to free the object
before either forgets its reference. Someone (I forget
who) submitted that { T:=A; A:=nil; T.Free; } _is_ safe
in this regard, but I would like to propose that when
using threads, not only is this code unsafe as well, but
A shouldn't be shared between threads at all, or, when this
form of code is necessary, it should be a critical section.
Nothing else will work.

(On a tangentially related note, apparently at least one
processor in the x86 family disabled interrupts following
a MOV SS, if the next instruction was a MOV SP. Did Borland
implement FreeAndNil as a critical section? Or perhaps in
two versions, switching when threads come into play?)

- Show quoted text -

Quote
>I don't know _any_ way that the way that I do it can go wrong.
>On the other hand setting objects to nil can induce a false
>sense of security. (Just curious: In your opinion _why_ is
>it that it took until D5(D4?) for Borland to add FreeAndNil
>to the language? People started asking for it as soon as D1
>came out. You think the guys at Borland couldn't figure out
>how to do it? I tend to suspect that they thought it was a
>bad idea, and finally bowed to popular demand. Better
>programmers than me share this opinion, btw.)

>False sense of security:

>var B: TSomeObject;

>Somewhere else:

>A:= B;
>A.Something;
>A.Free;
>A:= nil;

>and now somewhere else:

>B.Free;

>And you have your double-free kaboom in spite of the
>fact that you set your pointer to nil.

You're almost right. The problem here is the aliasing;
this can be solved (if it is applicable) by setting B
to nil directly after copying its value to A. Again,
if multiple thread share A and B this, too, should be
in a critical section.

Quote
>So you avoid that by being careful about the scope
>of things. But if you're just a little more careful
>about scope then there's no need for the := nil
>at all, and things are even _safer_.

Nice work if you can get it.

- Show quoted text -

Quote
>>Note that I _do assume that the destructor of "theObject" will not
>>somehow refer to us and attempt either to use us or to destroy us.  This
>>also would result in {*word*193} recursion and double-frees.

>>The scenario I was encountering was not recursive, but in the sequence:
>> a.Free;
>> b.Free;
>> a := nil;
>> b := nil;
>>... in step #2 the destructor of 'b' referenced us, found 'a', and tried
>>to free it a second time.  One moment I was in Windows... the next
>>moment Windows was completely gone and I was staring at my "$10,000 DOS
>>prompt."

>Well that just seems like bad programming to begin with. Objects
>should have clearly-defined owners - A.Destroy should not free
>anything except for fields A.FWhatever that it created in the
>constructor, and these objects should not be _available_ for code
>from outside the object to free. If you have destructors reaching
>out into the universe and freeing other objects I'm surprised you
>don't have more problems.

Although I sympathise with the loss of face as well as ten
thousand dollars, I cannot but agree with this wholeheartedly.
The usual construction is that objects maintain a list of
references, and as a "courtesy" free all the objects they
refer to in their own destructor. This is wrong, wrong, wrong.
It is proper to signal those objects that they are being
removed from the queue, but they should never be destroyed
in such a situation. Indeed, the only objects that should
be destroyed from a destructor are completely embedded
objects, whose lifetime is totally under another object's
control _and_ that are not available directly as object
references to outside code.

Which brings me directly to the coding construct where I
_do_ use { A.Free; A:=nil; } because I consider it necessary.
The following may be a bit protracted, I'm sorry if it does
not read very easily.

All my classes use the same code sequences in their
constructors and destructors. There are three private
procedures Wipe, Init, and Setup.

Constructors call { Init; inherited; Setup; }
Destructors call { Wipe; inherited; }
Wipe does { F.Free; F:=nil; } for all embedded objects
Init does { Wipe; F:=TF.Create; } for all embedded objects

Setup sets non-null default property values. Init also
sets null property values. Neither of those functionalities
is relevant to this discussion.

The reason for this seemingly strange convention is that
Create can be used as an object re-initialisator as well
as an object constructor. You can call Create on an existing
object, and it will re-create the object, resetting all its
properties to their default values, allocating new copies of
all embedded objects, but _not_ change the memory allocation
for the object itself. This is documented, although I do
not think even the VCL is as meticulous about it as I am.

This reset function interferes with both normal construction
and normal destruction of objects. During normal construction,
fields will have null values, but during an object reset,
they will not. { F.Free; F:=nil; } resolves this. Setting
the fields to nil is necessary because the object references
do not go out of scope. They could be left to point into
limbo, but I find this distasteful and worse, some properties
might be computed or allocated on first use. Wipe is shared
between the destructor(s) and Init to prevent code duplication.

It's perhaps a bit weak (I didn't realise this until now,
just as I didn't realise until this whole thread that FreeAndNil
is properly a critical section). It might be argued that both
when destroying and when resetting an object, embedded object
references can safely be left in fields. In the former case,
the object is being destroyed anyway, and in the latter case
Wipe is being called from Init, which will allocate a new
embedded object shortly (or clear the reference for on-demand
resolution). My point remains, however, that there are cases
where your claimed panacea of keeping object references valid
until the reference goes out of scope, is not always available.
I will grant that even in my example, it _is_ possible (and
effected) to guarantee that variables always contain valid
object references throughout their lifetime, with only short
and controlled exceptions.

Quote
>Um. When I say "should" above I suppose I should qualify that -
>the way I think things should be done is not the only way. But
>the way I do these things _is_ very very very safe - what I say
>in the previous paragraph is a necessary part of making it safe.
>(Necessary if you're doing it "my" way, not that it's _my_ way,
>I gleaned it from the docs and the source.)

I think I'd like to see a representative sample of your code
some time. Do you think we could arrange this? There's some
of mine I could let you take a look at and comment on, too.

Groetjes,
Maarten Wiltink

Re:Destructor Question


Quote
"Maarten Wiltink" <maar...@kittensandcats.net> wrote in message

news:9vbagc$t20

Quote
> IF threads are involved, { A.Free; A:=nil; } isn't safe
> because competing threads can both try to free the object
> before either forgets its reference. Someone (I forget
> who) submitted that { T:=A; A:=nil; T.Free; } _is_ safe
> in this regard, but I would like to propose that when
> using threads, not only is this code unsafe as well, but
> A shouldn't be shared between threads at all, or, when this
> form of code is necessary, it should be a critical section.
> Nothing else will work.

IIRC in D5 FreeAndNil is not in a critical section. Anyone writing
multi-threaded code were the threads share data structures should provide
protected access to the structures (be it a critical section, spin lock,
etc.). Not doing so is simply asking for trouble.

Quote
> for the object itself. This is documented, although I do
> not think even the VCL is as meticulous about it as I am.

You are right, the VCL is far from meticulous in this.

Quote
> resolution). My point remains, however, that there are cases
> where your claimed panacea of keeping object references valid
> until the reference goes out of scope, is not always available.
> I will grant that even in my example, it _is_ possible (and
> effected) to guarantee that variables always contain valid
> object references throughout their lifetime, with only short
> and controlled exceptions.

Once one starts to think in terms of designing out invalid references its
suprising how rarely one can't do it. While David suggested keeping object
references valid for their entire scope, I think that was a bit of an over
simplification. Its not required that an object reference always be valid,
just that it be valid when one has to read the reference.

Re:Destructor Question


"Bruce Roberts" <b...@bounceitattcanada.xnet> skrev i melding
news:F5eS7.4815$Q06.27797@tor-nn1.netcom.ca...

Quote

> "Maarten Wiltink" <maar...@kittensandcats.net> wrote in message
> news:9vbagc$t20

> > IF threads are involved, { A.Free; A:=nil; } isn't safe
> > because competing threads can both try to free the object
> > before either forgets its reference. Someone (I forget
> > who) submitted that { T:=A; A:=nil; T.Free; } _is_ safe
> > in this regard, but I would like to propose that when
> > using threads, not only is this code unsafe as well, but
> > A shouldn't be shared between threads at all, or, when this
> > form of code is necessary, it should be a critical section.
> > Nothing else will work.

> IIRC in D5 FreeAndNil is not in a critical section. Anyone writing
> multi-threaded code were the threads share data structures should provide
> protected access to the structures (be it a critical section, spin lock,
> etc.). Not doing so is simply asking for trouble.

> > for the object itself. This is documented, although I do
> > not think even the VCL is as meticulous about it as I am.

> You are right, the VCL is far from meticulous in this.

> > resolution). My point remains, however, that there are cases
> > where your claimed panacea of keeping object references valid
> > until the reference goes out of scope, is not always available.
> > I will grant that even in my example, it _is_ possible (and
> > effected) to guarantee that variables always contain valid
> > object references throughout their lifetime, with only short
> > and controlled exceptions.

> Once one starts to think in terms of designing out invalid references its
> suprising how rarely one can't do it. While David suggested keeping object
> references valid for their entire scope, I think that was a bit of an over
> simplification. Its not required that an object reference always be valid,
> just that it be valid when one has to read the reference.

The same goes for VCL access, too - you usually don't need that many "points
of synchronization". Two threads freeing up the same object ? That would
represent some miniature Code Hell, if that could *possibly* occur....

I'm questioning the idea of a Thread-safe VCL, I believe...;-)

--
Bjoerge Saether
Asker, Norway
bjorge@hahaha_itte.no (remve the obvious)

Go to page: [1] [2]

Other Threads