Heh, I actually donated that SafeGuard code to JCL many years ago. They modified the name a little, but not the concept. It works, but I am not sure if all guarded objects will be released on an exception. You'll have to test that. The advantage is indeed that you don't have to cast or anything. You use the original object you created. Yesterday, I even wrote a better approach, using records an implicit and explict casts. That one is certain to work and does not need a cast and the pointer can be used as if it were the actual object (by implicit cast).
type
IObjectGuard<T: class> = interface
function Value: T;
end;
TObjectGuard<T: class> = class(TInterfacedObject, IObjectGuard<T>)
private
FValue: T;
public
constructor Create(Obj: T);
destructor Destroy; override;
function Value: T;
end;
SmartPtr<T: class> = record
private
FGuard: IObjectGuard<T>;
public
class operator Explicit(const Obj: T): SmartPtr<T>;
class operator Implicit(const Ptr: SmartPtr<T>): T;
end;
{ TObjectGuard<T> }
constructor TObjectGuard<T>.Create(Obj: T);
begin
FValue := Obj;
end;
destructor TObjectGuard<T>.Destroy;
begin
FValue.Free;
inherited;
end;
function TObjectGuard<T>.Value: T;
begin
Result := FValue;
end;
{ SmartPtr<T> }
class operator SmartPtr<T>.Explicit(const Obj: T): SmartPtr<T>;
begin
Result.FGuard := TObjectGuard<T>.Create(Obj);
end;
class operator SmartPtr<T>.Implicit(const Ptr: SmartPtr<T>): T;
begin
if Ptr.FGuard <> nil then
Result := Ptr.FGuard.Value
else
Result := nil;
end;
And it can be used like:
var
Bob, Fred, Jack: TTalking;
begin
Bob := SmartPtr<TTalking>(TTalking.Create('Bob'));
Fred := SmartPtr<TTalking>(TTalking.Create('Fred'));
Jack := SmartPtr<TTalking>(TTalking.Create('Jack'));
Fred.Talk;
Bob.Talk;
raise Exception.Create('Error Message');
Jack.Talk;
Writeln('This is the end of the routine');
end;
As you can see, this also creates guards. They do work, even with the Exception. All are freed when the exception occurs.