i'm wondering when an instance of a TInterfacedObject derived class is destroyed and who calls the destructor. I wrote a ScopedLock class, which should automatically call the Release method of a synchronization object when the instance goes out of scope. It's an RAII concept known from C++, but i don't know if it is guaranteed that the destructor is called, when the lock instance goes out of scope.
ILock = interface
end;
ScopedLock<T: TSynchroObject> = class(TInterfacedObject, ILock)
strict private
sync_ : T;
public
constructor Create(synchro : T); reintroduce;
destructor Destroy;override;
end;
implementation
{ ScopedLock<T> }
constructor ScopedLock<T>.Create(synchro: T);
begin
inherited Create;;
sync_ := synchro;
sync_.Acquire;
end;
destructor ScopedLock<T>.Destroy;
begin
sync_.Release;
inherited;
end;
{ Example }
function Example.Foo: Integer;
var
lock : ILock;
begin
lock := ScopedLock<TCriticalSection>.Create(mySync);
// ...
end; // mySync released ?
It works fine in a simple test case, but is it safe?
Yes, that is save. Your code
function Example.Foo: Integer;
var
lock : ILock;
begin
lock := ScopedLock<TCriticalSection>.Create(mySync);
// ...
end;
is compiled as the following pseudocode
function Example.Foo: Integer;
var
lock : ILock;
begin
lock := ScopedLock<TCriticalSection>.Create(mySync);
lock._AddRef; // ref count = 1
try
// ..
finally
lock._Release; // ref count = 0, free lock object
end;
You can see that when lock var goes out of scope its ref count is decremented, became zero and lock object is automatically destroyed.
The only problem is if the function is inlined: the local variable containing the ILock reference will be promoted to the scope of the function calling the inlined function. That may cause the lock to live longer than you wanted.
On the other hand, there's no need to actually declare a variable to hold the interface reference, if you write a function (e.g. a class function called Create) that returns an interface reference (as opposed to an object reference). The compiler will create a hidden local to receive the return value (as all managed types like interfaces and strings are actually returned by passing a result variable). This hidden local will act just like the explicit local.
I wrote more about it here: http://blog.barrkel.com/2010/01/one-liner-raii-in-delphi.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With