Board index » delphi » A/V in destructor

A/V in destructor

In developing some sameple code for a linked list implementation of a stack
I decided to declare a second destructor for the stack entries class.
Unfortunately when the destructor is used an a/v is generated following
execution of the destructor (before the debuger returns to the caller). I'd
like to understand why this is.

Type

tIntegerStackEntry = class (tObject)
  private
    fValue : integer;
    fNext : tIntegerStackEntry;
  public
    constructor CreateEx (aValue : integer; nxt : tIntegerStackEntry);
    destructor DestroyEx (var aValue : integer; var nxt :
tIntegerStackEntry);
  end;

tIntegerStack = class (tObject)
  private
    fTOS : tIntegerStackEntry;
    fStackSize : Integer;
  public
    destructor Destroy; override;
    procedure Push (aValue : Integer);
    function Pop : Integer;
    function Peek : Integer;
    function isEmpty : boolean;
    property Height : Integer read fStackSize;
    end;

constructor tIntegerStackEntry.CreateEx (aValue : integer; nxt :
tIntegerStackEntry);

begin
Create;
fValue := aValue;
fNext := nxt;
end;

destructor tIntegerStackEntry.DestroyEx (var aValue : integer; var nxt :
tIntegerStackEntry);

begin
aValue := fValue;
nxt := fNext;
Destroy;
end;                // <<<< failure point

procedure tIntegerStack.Push (aValue : integer);

begin
fTOS := tIntegerStackEntry.CreateEx (aValue, fTOS);
inc (fStackSize);
end;

function tIntegerStack.Pop : integer;

begin
if Assigned (fTOS)
then begin
     fTOS.DestroyEx (Result, fTOS);
     dec (fStackSize);
     end
else raise exception.Create ('Pop of empty stack');
end;

destructor tIntegerStack.Destroy;

var dontCare : integer;

begin
while Assigned (fTOS) do
     fTOS.DestroyEx (dontCare, fTOS);
inherited Destroy;
end;

function tIntegerStack.Peek : integer;

begin
if Assigned (fTOS)
then result := fTOS.fValue
else raise exception.Create ('Peek at empty stack');
end;

function tIntegerStack.isEmpty : boolean;

begin
result := fStackSize = 0;
end;

 

Re:A/V in destructor


"Bruce Roberts" <b...@bounceitattcanada.xnet> skrev i melding
news:RVWe9.10887$H67.55816@tor-nn1.netcom.ca...

Quote
> In developing some sameple code for a linked list implementation of a
stack
> I decided to declare a second destructor for the stack entries class.
> Unfortunately when the destructor is used an a/v is generated following
> execution of the destructor (before the debuger returns to the caller).
I'd
> like to understand why this is.

[...]

Quote
> destructor tIntegerStackEntry.DestroyEx (var aValue : integer; var nxt :
> tIntegerStackEntry);

> begin
> aValue := fValue;
> nxt := fNext;
> Destroy;
> end;                // <<<< failure point

I believe the reason is, the call to Destroy; is compiled as a complete
destructor call, that is, the automagical FreeInstance; etc., is invoked at
the end of the call. At the very next line you do it again, and you have
your AV.

Try:

  inherited Destroy;

...and I believe the compiler will make it a regular method call, not a
*new* destruction call.

--
Bj?rge S?ther
bjorge@hahaha_itte.no

Re:A/V in destructor


Quote
"Bj?rge S?ther" <bjorge@hahaha_itte.no> wrote in message news:H7Ye9.15638
> > destructor tIntegerStackEntry.DestroyEx (var aValue : integer; var nxt :
> > tIntegerStackEntry);

> > begin
> > aValue := fValue;
> > nxt := fNext;
> > Destroy;
> > end;                // <<<< failure point

> I believe the reason is, the call to Destroy; is compiled as a complete
> destructor call, that is, the automagical FreeInstance; etc., is invoked
at
> the end of the call. At the very next line you do it again, and you have
> your AV.

> Try:

>   inherited Destroy;

I did try that. I also tried commenting out any call to Destroy, inherited
or not, in the destructor. All with exactly the same results. I'm beginning
to wonder if the problem is with having the parameters. I've tried both var
and out, with the same results. Since my original post I tried a version
without the parameters and the error doesn't arise. So it seems that having
parameters, at least pass-by-reference, on a destructor causes some
problems. But I can't recall ever seeing anything in the help or ng
regarding this.

Re:A/V in destructor


In article <%86f9.10948$H67.56...@tor-nn1.netcom.ca>, "Bruce Roberts"

Quote
<b...@bounceitattcanada.xnet> writes:
> I'm beginning
>to wonder if the problem is with having the parameters.

Bruce

I wonder if you've seen this in D3 help ...

"Constructors and destructors
Constructors and destructors use the same calling conventions as other methods,
except that an additional Boolean flag parameter is passed to indicate the
context of the constructor or destructor call.
<snip>
A value of False in the flag parameter of a destructor call indicates that the
destructor was invoked using the inherited keyword. In this case, the
destructor behaves like an ordinary method.
A value of True in the flag parameter of a destructor call indicates that the
destructor was invoked through an instance. In this case, the destructor
deallocates the instance given by Self just before returning.
For all calling conventions, the Boolean flag parameter behaves as if it was
declared before all other parameters. Thus, with the register convention, the
flag is always passed in the DL register, with the pascal convention, the flag
is always pushed before all other parameters, and with the cdecl, stdcall and
safecall conventions, the flag is always pushed right before the Self
parameter."

... and ...

"Destructors
<snip>
While it is possible to declare multiple destructors for a class, it is
recommended that classes only implement overrides of the inherited Destroy
destructor. Destroy is a parameterless virtual destructor declared in TObject,
and because TObject is the ultimate ancestor of every class, the Destroy
destructor always available for any object.
<snip>"

It sounds as thought something strange is being wrought. Perhaps the destructor
gets confused if parameters appear, particularly parameters whose numbers fill
the available registers.

Alan Lloyd
alangll...@aol.com

Re:A/V in destructor


Quote
"AlanGLLoyd" <alangll...@aol.com> wrote in message
> A value of False in the flag parameter of a destructor call indicates that

the

<. . .>

Quote
> parameter."

I hand't recalled this part.

Quote
> While it is possible to declare multiple destructors for a class, it is
> recommended that classes only implement overrides of the inherited Destroy
> destructor. Destroy is a parameterless virtual destructor declared in
TObject,
> and because TObject is the ultimate ancestor of every class, the Destroy
> destructor always available for any object.

Yeah, but they don't say you can't do it :).

Quote
> It sounds as thought something strange is being wrought. Perhaps the
destructor
> gets confused if parameters appear, particularly parameters whose numbers
fill
> the available registers.

I think your surmise is on the right track. I just tried the code with
pass-by-value parameters and inherited Destroy, no a/v in the destructor. Of
course the stack doesn't work :).

Its not a big deal, I wouldn't use this sort of code anyway. It just that I
wanted to understand why it didn't work.

Re:A/V in destructor


Quote
> Its not a big deal, I wouldn't use this sort of code anyway. It just that
I
> wanted to understand why it didn't work.

Maybe it is worth having a look at the implementation of TStack, just to see
how Borland implemented it (I believe they use a TList, so you may have to
look into that one as well).

- daniel

Re:A/V in destructor


Quote
"Daniel Rutten" <n...@junk.com> wrote in message

news:1031638308.229962@cereal.attica.net.nz...

Quote
> Maybe it is worth having a look at the implementation of TStack, just to
see
> how Borland implemented it (I believe they use a TList, so you may have to
> look into that one as well).

I'm not really interested in creating a stack. The few times I've needed one
I've either used tStack or a ring buffer. It all started out with me writing
some sample code that implemented a linked list stack. In doing so I had,
what I thought at the time, a neat way of handling the element pushing and
popping. Turns out not to be workable in ObjectPascal. But the reason it
isn't workable was a surprise. The fact that the code compiles leads one to
believe that by-reference parameters on destructors are acceptable (as they
should be, IMO). Alas, this doesn't seem to be the case.

Re:A/V in destructor


"Bruce Roberts" <b...@bounceitattcanada.xnet> skrev i melding
news:xzhf9.11005$H67.55922@tor-nn1.netcom.ca...

Quote

> "Daniel Rutten" <n...@junk.com> wrote in message
> news:1031638308.229962@cereal.attica.net.nz...

> > Maybe it is worth having a look at the implementation of TStack, just to
> see
> > how Borland implemented it (I believe they use a TList, so you may have
to
> > look into that one as well).

> I'm not really interested in creating a stack. The few times I've needed
one
> I've either used tStack or a ring buffer. It all started out with me
writing
> some sample code that implemented a linked list stack. In doing so I had,
> what I thought at the time, a neat way of handling the element pushing and
> popping. Turns out not to be workable in ObjectPascal. But the reason it
> isn't workable was a surprise. The fact that the code compiles leads one
to
> believe that by-reference parameters on destructors are acceptable (as
they
> should be, IMO). Alas, this doesn't seem to be the case.

Well, it doesn't ruin your concept, just to read the values through an extra
method just before the destroy; line:

procedure tIntegerStackEntry.GetValues(var aValue : integer; var nxt :
tIntegerStackEntry);
begin
  aValue := fValue;
  nxt := fNext;
end;

function tIntegerStack.Pop : integer;
var
  Next: tIntegerStackEntry;
begin
if Assigned (fTOS)
then begin
     fTOS.GetValues(Result, Next);
     fTOS.Destroy;
     dec (fStackSize);
     end
else raise exception.Create ('Pop of empty stack');
end;

destructor tIntegerStack.Destroy;

var
  dontCare : integer;
  Next: tIntegerStackEntry;

begin
while Assigned (fTOS) do begin
  fTOS.GetValues(dontCare, Next);
  fTOS.Destroy;
  fTOS:=Next;
end;
inherited Destroy;
end;

...although I agree it's not as elegant...but simpler to read & understand.

--
Bj?rge S?ther
bjorge@hahaha_itte.no

Re:A/V in destructor


Im Artikel <RVWe9.10887$H67.55...@tor-nn1.netcom.ca>, "Bruce Roberts"
<b...@bounceitattcanada.xnet> schreibt:

Quote
>destructor tIntegerStackEntry.DestroyEx (var aValue : integer; var nxt :
>tIntegerStackEntry);

>begin
>aValue := fValue;
>nxt := fNext;
>Destroy;
>end;                // <<<< failure point

It works for me in D4, when using "inherited Destroy;". Without "inherited"
both Destroy or Free give an A/V, but just on that statement, not at the
execution of (the hidden code at) "end"!

It also didn't help to override the Destroy destructor, even if that destructor
does nothing.

I'd suggest that you add "inherited", or simply omit the call to Destroy. There
is no obligation to call inherited destructors, in detail when in your case
TObject.Destroy does nothing at all.

DoDi

Re:A/V in destructor


Quote
"VBDis" <vb...@aol.com> wrote in message

news:20020910050923.22641.00000758@mb-

Quote
> It works for me in D4, when using "inherited Destroy;". Without
"inherited"
> both Destroy or Free give an A/V, but just on that statement, not at the
> execution of (the hidden code at) "end"!
> I'd suggest that you add "inherited", or simply omit the call to Destroy.
There
> is no obligation to call inherited destructors, in detail when in your
case
> TObject.Destroy does nothing at all.

I've tried both with the same results in D5. Guess its time to dig out D3
and see if that causes a difference. See below for minimal test code.
DestroyEx fails with an a/v, DestroyExAlso doesn't.

Type
tFoo = class (tObject)
  public
     destructor DestroyEx (var anInt : integer);
     destructor DestroyExAlso (anInt : integer);
  end;

destructor tFoo.DestroyEx (var anInt : integer);

begin
anInt := 5;
inherited Destroy;
end;

destructor tFoo.DestroyExAlso (anInt : integer);

begin
anInt := 5;
inherited Destroy;
end;

Re:A/V in destructor


Quote
> There
> is no obligation to call inherited destructors, in detail when in your
case
> TObject.Destroy does nothing at all.

... yet... I always call the inherited destory, even of TObject, just in
case Borland changes the VCL and add some stuff to the TObject.Destroy. One
worry less when upgrading to a new Delphi version.

- daniel

Re:A/V in destructor


I agree with that.  

The _first_ statement in all of my constructors is a call to the inherited
constructor.  The _last_ statement is a call to the inherited destructor.

(n.b. Pay attention to "virtual."  Do a "build all" and clean up _all_
hints.)

Quote
>Daniel Rutten wrote:

>> There
>> is no obligation to call inherited destructors, in detail when in your
> case
>> TObject.Destroy does nothing at all.

> ... yet... I always call the inherited destory, even of TObject, just in
> case Borland changes the VCL and add some stuff to the TObject.Destroy.
> One worry less when upgrading to a new Delphi version.

Re:A/V in destructor


On Wed, 25 Sep 2002 15:23:11 -0700, Sundial Services

Quote
<info_...@sundialservices.com> wrote:
> I agree with that.  

> The _first_ statement in all of my constructors is a call to the inherited
> constructor.  The _last_ statement is a call to the inherited destructor.

BTW,

  inherited;

is to be preferred over

  inherited Destroy;

IMO. Perhaps not necessarily in this case, but generally inherited
without qualification behaves differently than with.
--
Rudy Velthuis

Re:A/V in destructor


Quote
"Daniel Rutten" <n...@junk.com> wrote in message
> ... yet... I always call the inherited destory, even of TObject, just in
> case Borland changes the VCL and add some stuff to the TObject.Destroy.
One
> worry less when upgrading to a new Delphi version.

Me too. While Borland may never change the destructor of tObject, its
reasonably likely that the descendant's ancestry may be altered. A firm
rule, IMO, is that if a method is virtual, always call the inherited method.
(Unless of course one really doesn't want the inherited behavior.)

Re:A/V in destructor


Quote
"Rudy Velthuis" <rvelth...@gmx.de> wrote in message
>   inherited;

> is to be preferred over

>   inherited Destroy;

> IMO. Perhaps not necessarily in this case, but generally inherited
> without qualification behaves differently than with.

What is the reasoning for this preference? Personally I've always preferred
the second, more explicit, form.
Go to page: [1] [2]

Other Threads