When TInterfacedObject.Destroy (ScopedLock class) is called

I am wondering when the instance of the derived class TInterfacedObject is destroyed and who calls the destructor. I wrote the ScopedLock class, which should automatically call the Release method of the synchronization object when the instance goes out of scope. This is a RAII concept known from C ++, but I don’t know if the destructor is guaranteed to be 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 great in a simple case, but is it safe?

+4
source share
3 answers

Yes, it saves. Your code

 function Example.Foo: Integer; var lock : ILock; begin lock := ScopedLock<TCriticalSection>.Create(mySync); // ... end; 

compiled as 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 the var lock goes out of scope, its number of links decreases, becomes zero, and the lock object is automatically destroyed.

+5
source

The only problem is that the function is built-in: the local variable containing the ILock link will advance into the scope of the function that calls the built-in function. This may cause the castle to live longer than you wanted.

On the other hand, there is no need to actually declare a variable to store a reference to an interface if you write a function (for example, a class function called Create) that returns a link to the interface (as opposed to an object reference). The compiler will create a hidden local object to get the return value (since all managed types, such as interfaces and strings, are actually returned by passing the result variable). This hidden locale will act just like an explicit local one.

I wrote about this in more detail: http://blog.barrkel.com/2010/01/one-liner-raii-in-delphi.html

+6
source

I do not see that the approach that you support, although correct, is actually better than the good old Try / finally. You made a clear and concise decision and replaced it with an obscure and opaque one.

Real work. Delphi code is full of Try / finally, and therefore should be a natural idiom. I see no shortage of spelling:

 mySync.Acquire; Try //do stuff Finally mySync.Release; End; 
0
source

All Articles