Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The most effective way to make sure something cannot be instantiated is by making it a pure abstract class. That is, if you care enough to heed compiler hints and warnings.</p> <p>Then define a function in the implementation section that returns a reference to that abstract class. Like Cosmin does in one of his answers. </p> <p>The implementation section implements that function (you can even make use of lazy instantiation here, as Cosmin also shows/ed).</p> <p>But the crux is to have a concrete class declared and implemented in the <strong>implementation</strong> section of the unit so only the unit can instantiated it.</p> <pre><code>interface type TSingleton = class(TObject) public procedure SomeMethod; virtual; abstract; end; function Singleton: TSingleton; implementation var _InstanceLock: TCriticalSection; _SingletonInstance: TSingleTon; type TConcreteSingleton = class(TSingleton) public procedure SomeMethod; override; end; function Singleton: TSingleton; begin _InstanceLock.Enter; try if not Assigned(_SingletonInstance) then _SingletonInstance := TConcreteSingleton.Create; Result := _SingletonInstance; finally _InstanceLock.Leave; end; end; procedure TConcreteSingleton.SomeMethod; begin // FLock can be any synchronisation primitive you like and should of course be // instantiated in TConcreteSingleton's constructor and freed in its destructor. FLock.Enter; try finally FLock.Leave; end; end; </code></pre> <p>That said, please bear in mind that there are plenty of problems using singletons: <a href="http://jalf.dk/blog/2010/03/singletons-solving-problems-you-didnt-know-you-never-had-since-1995/" rel="nofollow">http://jalf.dk/blog/2010/03/singletons-solving-problems-you-didnt-know-you-never-had-since-1995/</a></p> <p><strong>Thread safety</strong></p> <p>David is absolutely right in his comment that I was wrong before about the function not needing any protection. The instantiation <em>does</em> indeed need protecting or you could end up with two (possibly more) instances of the singleton and several of them in limbo with regard to freeing (which would be done in the finalization section as with many lazy instantion mechanisms). So here is the amended version.</p> <p>To get thread safety in this setup, you need to protect the instantiation of the singleton and you need to protect all methods in the concrete class that are publicly available through its abstract ancestor. Other methods do not need to be protected as they are only be callable through the publicly available ones and so are protected by the protection in those methods.</p> <p>You can protect this by a simple critical section, declared in the implementation, instantiated in the initialization and free in the finalization section. Of course the CS would have to protect the freeing of the singleton as well and should therefore be freed afterwards.</p> <p>Discussing this with a colleague, we came up with a way to (mis)/(ab)use the instance pointer itself as a sort of lock mechanism. It would work, but I find it to ugly to share with the world at this point in time...</p> <p>What synchronisation primitives are used to protect the publicly callable methods is entirely up to the "user" (coder) and may tailored to the purpose the singleton.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload