Jens
Rgds,
Martin
Just an idea...
destructor TMyObject.Destroy;
begin
try
ThisMightRaiseAnException;
finally
inherited;
end;
end;
But then again, if the inherited destructor is implemented in this way,
too, and both destructors raise an exception, what happens? Generally
spoken: What happens if an exception is raised in the finally section of
a try-block? Two exceptions pending at the same time is impossible,
isn't it?
Jens
<g> Yes, I seem to remember a thread about this, or a similar, subject some
months ago.
Rgds,
Martin
Better, yes. Does not help with:
destructor TMyObject.Destroy;
begin
try
ThisMightRaiseAnException;
bigComplexObject.free;
finally
inherited;
end;
end;
You could nest the try-finallies to try & force the execution of every line
in every destructor in the hierarchy, but this seems very messy.
Maybee TObject should have an 'onDestroyFail' event that is called whenever
there is a problem in a destructor, rather than raising an exception in the
usual way. This might allow control to return to the destructor that had
experienced the problem & so finish cleaning up its other objects and
calling 'inherited'.
> But then again, if the inherited destructor is implemented in this way,
> too, and both destructors raise an exception, what happens?
Err.. hmm.. maybee time for an experiment :)
> Generally
> spoken: What happens if an exception is raised in the finally section of
> a try-block? Two exceptions pending at the same time is impossible,
> isn't it?
Not at all sure..
Rgds,
Martin
> <g> Yes, I seem to remember a thread about this, or a similar, subject
some
> months ago.
Yes, I had a stupid question on rollbacks. This is sorta different. In fact,
i suppose an administrator intervention is required to resolve the stalls
when you cannot neither proceed nor get back. This situaton must be
especially thoroughly polished in banking transaction theory due to
catastrophic consequencies of misbihaviour and distributed nature of the
systems (connection is not a reliable medium). So far, I have been satisfied
by this responce:
http://groups-beta.google.com/group/microsoft.public.win32.programmer.kernel/msg/1af76c303bc16eac?dmode=source .
The idea that the release routines must always succeed looks attractive but
not realistic. So, I waiting for links on more elaborative dissretations.
It's easy to test. Running the following code you'll find out the
original exception is forgotten:
procedure TForm1.Button1Click(Sender: TObject);
begin
try
try
raise Exception.Create('Exception 1');
finally
raise Exception.Create('Exception 2');
end;
except
on E: Exception do
ShowMessage(Format('%s exception: "%s"', [E.ClassName,
E.Message]));
end;
end;
> This is sorta different. In fact,
> i suppose an administrator intervention is required to resolve the
> stalls when you cannot neither proceed nor get back. This situaton
> must be especially thoroughly polished in banking transaction theory
> due to catastrophic consequencies of misbihaviour and distributed
> nature of the systems (connection is not a reliable medium).
Well, if you want a *really* theory-based explanation of this problem,
read:
http://research.microsoft.com/pubs/ccontrol/
-Craig
--
Craig Stuntz [TeamB] . Vertex Systems Corp. . Columbus, OH
Delphi/InterBase Weblog : http://blogs.teamb.com/craigstuntz
Everything You Need to Know About InterBase Character Sets:
http://blogs.teamb.com/craigstuntz/articles/403.aspx
> I always thought raising exceptions in destructors is a bad habbit.
I agree:
http://blogs.teamb.com/craigstuntz/archive/2004/08/24/ATrickQuestionAndA
nImportantLesson.aspx
--
Craig Stuntz [TeamB] · Vertex Systems Corp. · Columbus, OH
Delphi/InterBase Weblog : http://blogs.teamb.com/craigstuntz
> Very interesting. So when an error can occur in a destructor (like in
> TCustomWinSocket.Destroy) it's probably better to ignore it silently
> ("Windos can not clean up my socket? Not my problem. I don't need it
> any more.").
I can't comment on that specific case since I'm not really familiar
with the component.
--
Craig Stuntz [TeamB] · Vertex Systems Corp. · Columbus, OH
Delphi/InterBase Weblog : http://blogs.teamb.com/craigstuntz
Want to help make Delphi and InterBase better? Use QC!
http://qc.borland.com -- Vote for important issues
Very interesting. So when an error can occur in a destructor (like in
TCustomWinSocket.Destroy) it's probably better to ignore it silently
("Windos can not clean up my socket? Not my problem. I don't need it any
more.").
Jens
Correct. The destructor does not finish running, and the memory for the
object is not released. You'll have a memory leak.
> Just an idea...
>
> destructor TMyObject.Destroy;
> begin
> try
> ThisMightRaiseAnException;
> finally
> inherited;
> end;
> end;
Since the exception does not get handled, the destructor will not finish
running. The memory is *not* released by the inherited destructor. Just
as an object is already fully allocated before any code in a constructor
runs, the object is not de-allocated until after all code in all
destructors runs.
At the end of each destructor is some hidden code, generated by the
compiler, that checks whether this is the out-most destructor for the
object. If it is, then special de-allocation code is called.
> But then again, if the inherited destructor is implemented in this way,
> too, and both destructors raise an exception, what happens? Generally
> spoken: What happens if an exception is raised in the finally section of
> a try-block? Two exceptions pending at the same time is impossible,
> isn't it?
Not impossible at all. Only one is active, though. The exceptions are
stored on a stack. You're allowed to have try-except and try-finally
blocks nested within the except and finally sections of other blocks,
and it all works just as you'd expect it to.
If an exception is raised in an except or finally block and not caught
before escaping the outer nested block, then the previous exception is
lost forever. I think the exception gets freed, but it is not accessible
to any other code.
In the following code, exception A will get caught by the inner except
block, but it will get discarded when B gets raised. The outer except
block catches B. Exception A gets freed, although I'm not certain of
when that happens.
try
try
raise Exception.Create('A');
except
on A: Exception do begin
S := TStringList.Create;
try
raise Exception.Create('B');
finally
S.Free;
end;
raise;
end;
end;
except
on B: Exception do Writeln(B.Message); // prints 'B'
end;
If the try-finally block had been a try-except block, then it would
catch and handle exception B. When execution reached the final "raise"
statement, exception A would get re-raised, and the outer except block
would catch A instead of B.
--
Rob