Using SafeGuards
This article describes SafeGuards -- an easy way of automatic resource destruction.
By Matthias Thoma
The Jedi Code Library's SafeGuards provide the functionality of automatic resource destruction.
This feature is not as powerful as automatic garbage collection which some programming languages provide but it is very useful anyway.
Everyone knows code that creates an object, works with the object and frees it again in the same procedure. SafeGuards are
especially appropriate in such situations.
An example of the create-work-free structure is illustrated in the following code:
var
bmp: TBitmap;
jpeg: TJPEGImage;
begin
bmp := TBitmap.Create;
jpeg := TJPEGImage.Create;
try
bmp.LoadFromFile('C:test.bmp');
jpeg.Assign(bmp);
jpeg.SaveToFile('C:test.jpg');
finally
bmp.free;
jpeg.free;
end;
Using SafeGuards, the code looks like this:
var
bmp: TBitmap;
jpeg: TJPEGImage;
is1, is2 : ISafeGuard;
begin
bmp := TBitmap(Guard(TBitmap.Create,is1));
jpeg := TJPEGImage(Guard(TJPEGImage.Create,is2));
bmp.LoadFromFile('C:test.bmp');
jpeg.Assign(bmp);
jpeg.SaveToFile('C:test.jpg');
end;
Another common situation is memory allocation:
var
p: pointer;
begin
try
GetMem(p,100000000);
// Work with p
finally
FreeMem(p);
end;
end;
Using SafeGuards:
var
p: pointer;
is1: ISageGuard;
begin
GetMem(p,100000000);
Guard(p,is1);
// Work with p
end;
or even easier:
var
p: pointer;
is1: ISageGuard;
begin
p := GuardAllocMem(100000000,is1);
// Work with p
end;
If you need proof - here it is:
procedure Prove;
var
p: pointer;
h: THeapStatus;
procedure AllocPointer(SGOn: Boolean);
var
is1: ISafeGuard;
begin
GetMem(p, 100000);
if SGON then
Guard(p,is1);
end;
begin
h := GetHeapStatus;
ShowMessage(inttostr(h.TotalAllocated));
AllocPointer(False); // Without SafeGuard
h := GetHeapStatus;
ShowMessage(inttostr(h.TotalAllocated));
FreeMem(p, 100000);
h := GetHeapStatus;
ShowMessage(inttostr(h.TotalAllocated));
AllocPointer(True); // SafeGuard
h := GetHeapStatus;
ShowMessage(inttostr(h.TotalAllocated));
end;
What is the secret? ISafeGuard is an interface. Delphi guarantees that an interface variable is released when it it leaves its
scope. So the resource is associated with the interface and is released together with the interface.
The function Guard is declared as:
function Guard(Mem: Pointer;
out SafeGuard: ISafeGuard):
pointer; overload;
function Guard(Obj: TObject;
out SafeGuard: ISafeGuard):
TObject; overload;
The results are copies of the input parameters Mem or Obj. This allows you to call Guard within functions. Other useful Guard-related functions are:
|
ISafeGuard.ReleaseItem
|
Disassociates the Resource from the SafeGuard. The responsibility of releasing the object is given back to you.
|
|
ISafeGuard.GetItem
|
Returns a pointer to the resource associated with the SafeGuard.
|
|
ISafeGuard.FreeItem
|
Frees the Item associated with the SafeGuard.
|
To download the Jedi Code Library please visit www.delphi-jedi.org