Embarcadero Delphi
Användning av försök, utom och slutligen
Sök…
Syntax
Försök med undantag: försök [uttalanden] förutom [[[på E: ExceptionType do statement]] [else statement] | [uttalanden] slut;
Försök äntligen: försök [uttalanden] slutligen [uttalanden] slut;
Enkelt försök .. slutligt exempel för att undvika minnesläckor
Använd try
- finally
att undvika läckande resurser (t.ex. minne) om ett undantag inträffar under körning.
Proceduren nedan sparar en sträng i en fil och förhindrar att TStringList
läcker.
procedure SaveStringToFile(const aFilename: TFilename; const aString: string);
var
SL: TStringList;
begin
SL := TStringList.Create; // call outside the try
try
SL.Text := aString;
SL.SaveToFile(aFilename);
finally
SL.Free // will be called no matter what happens above
end;
end;
Oavsett om ett undantag inträffar vid lagring av filen kommer SL
att frigöras. Alla undantag går till den som ringer.
Undantagssäker återkomst av ett nytt objekt
När en funktion returnerar ett objekt (i motsats till att använda ett som har skickats in av den som ringer), var noga med att ett undantag inte får objektet att läcka.
function MakeStrings: TStrings;
begin
// Create a new object before entering the try-block.
Result := TStringList.Create;
try
// Execute code that uses the new object and prepares it for the caller.
Result.Add('One');
MightThrow;
except
// If execution reaches this point, then an exception has occurred. We cannot
// know how to handle all possible exceptions, so we merely clean up the resources
// allocated by this function and then re-raise the exception so the caller can
// choose what to do with it.
Result.Free;
raise;
end;
// If execution reaches this point, then no exception has occurred, so the
// function will return Result normally.
end;
Naiva programmerare kan försöka fånga alla undantagstyper och återlämna nil
från en sådan funktion, men det är bara ett speciellt fall av den allmänna avskräckta praxisen att fånga alla undantagstyper utan att hantera dem.
Försök att äntligen kapsla in i try-utom
Ett try
- finally
block kan kapslas in i ett try
- except
block.
try
AcquireResources;
try
UseResource;
finally
ReleaseResource;
end;
except
on E: EResourceUsageError do begin
HandleResourceErrors;
end;
end;
Om ett undantag inträffar i UseResource
kommer ReleaseResource
att ReleaseResource
till ReleaseResource
. Om undantaget är en EResourceUsageError
, kommer exekveringen att hoppa till undantagshanteraren och anropa HandleResourceErrors
. Undantag av någon annan typ kommer att hoppa över undantagshanteraren ovan och bubbla upp till nästa try
- except
blockera samtalstaket.
Undantag i AcquireResource
eller ReleaseResource
orsakar exekveringen att gå till undantag handler, hoppa över finally
blocket, antingen på grund av motsvarande try
blocket inte har angetts ännu eller på grund av finally
blocket har redan matats in.
Försök-utom kapslade in try-slutligen
Ett try
- except
block kan kapslas in i ett try
- finally
blockera.
AcquireResource;
try
UseResource1;
try
UseResource2;
except
on E: EResourceUsageError do begin
HandleResourceErrors;
end;
end;
UseResource3;
finally
ReleaseResource;
end;
Om en EResourceUsageError
inträffar i UseResource2
, kommer exekveringen att hoppa till undantagshanteraren och ringa HandleResourceError
. Undantaget kommer att betraktas som hanterat, så körning fortsätter till UseResource3
och sedan ReleaseResource
.
Om ett undantag av någon annan typ förekommer i UseResource2
, då undantag handler show här inte kommer att gälla, så utförandet kommer att hoppa över UseResource3
samtalet och gå direkt till finally
blocket, där ReleaseResource
kommer att kallas. Därefter hoppas exekveringen till nästa tillämpliga undantagshanterare när undantaget bubblar upp samlingsstacken.
Om ett undantag inträffar i något annat samtal i exemplet HandleResourceErrors
kommer HandleResourceErrors
inte att HandleResourceErrors
. Detta beror på att inget av de andra samtalen inträffar i try
som motsvarar den undantagshanteraren.
Försök slutligen med två eller flera objekt
Object1 := nil;
Object2 := nil;
try
Object1 := TMyObject.Create;
Object2 := TMyObject.Create;
finally
Object1.Free;
Object2.Free;
end;
Om du inte initialiserar objekten med nil
utanför try-finally
blocket, om ett av dem inte skapas, kommer en AV att inträffa på det slutliga blocket, eftersom objektet inte kommer att vara noll (eftersom det inte initialiserades) och kommer att orsaka ett undantag.
Metoden Free
kontrollerar om objektet är noll, så att initiera båda objekten med nil
undviker fel när de frigörs om de inte skapades.