Boost logo

Boost :

From: Jason Hise (chaos_at_[hidden])
Date: 2005-01-11 17:07:23


Mithun R K wrote:

>Hello, Jason/all.
>
>I find the discussion around the new/improved Singleton template very
>exciting.
>
>Perhaps a month ago, I'd written a Singleton class template in a manner
>similar to Jason's initial approach (though not *nearly* as
>cool/customizable). I.e.
>
>template < typename T, int Longevity = static_cast<int>( T::Longevity ) >
>struct Singleton : public SingletonBase, public T
>{...};
>
>My approach was:
>
>1. Have a single SingletonRegistry that would keep pointers to all Singleton
>instances (well, actually, SingletonBase instances. SingletonBase is not a
>class-template.)
>2. Each instance has a longevity-int associated with it. At
>destruction-time, we sort the singleton-instances based on their relative
>longevities, and destroy the objects in order.
>It's kinda up to the "client" of Singleton<T> to figure out the
>collaboration between her classes, and assign longevity-values to her
>classes.
>3. Singleton<T> instances are "registered" with the SingletonRegistry, by
>its constructor.
>4. Singleton<T>::~Singleton() lets the registry know that the instance may
>be destroyed. The SingletonRegistry destroys the instance if all singletons
>with a lesser longevity have already been marked for destruction. (I guess
>that's simple mark-and-sweep.)
>
>I'd be honoured and grateful if anyone has comments on this approach.
>
This is interesting. The main problem that your code introduces is in
the SingletonRegistry, by keeping pointers to the non-template base. By
making this non-template base mandatory, I would think that making
destructors virtual would become mandatory, and introduce much
overhead. The method I plan to use will keep pointers to static Create
and Destroy methods (which the templated LongevityLifetime will
introduce). This way the SingletonRegistry can maintain a stack of
nodes that have pointers to the create and destroy methods, without
needing to actually have access to the singleton instance itself.

>I have a couple of (naïve?) questions regarding the new approach. Please
>bear with me:
>
>1. Why was the old approach abandoned in favour of CRTP? The reason I went
>with the above was that I wanted Singleton<T>& to be able to replace T&. I
>wanted the Singleton template to fit around an existing class definition, as
>inobtrusively as possible. Would somebody kindly clarify?
>
>
The two problems mentioned with my previously used approach (anyone
correct me if I missed one) was that it introduced virtual functions,
and that typing out Singleton < Important > was harder than just writing
out Important. In my old model it would have made it illegal to create
an instance of Important, and thus a singleton around that type wouldn't
really be an unobtrusive wrapper, in that it would disable any code
already using the class as a non singleton. The new method simply cuts
out some unnecessary syntax.

>2. At least in Jason's first version, the Singleton class-template had a
>static Singleton<T> instance. Wouldn't that cause the instance to *always*
>be instantiated at load-time?
>
Au contraire! In fact, the original version had a static *pointer* to
the singleton. What was causing the singleton to always be instantiated
before main was the static dependency, which I quickly eliminated upon
discovering that this behavior is not always desirable.

>3. Say an application uses multiple shared libs. Say Singleton<MyClass> is
>used in more than one library. The definition of the static
>singleton-instance is in the template header (assuming that we're not using
>template exports, and all this stuff is inline). There's a good chance that
>the definition of Singleton<MyClass> might be generated multiply in
>different libraries of the same app. Won't that mean that there will be more
>than 1 instance of Singleton<MyClass>? I'm not sure how to get around this
>right now. Ideas?
>
>
I suspect that the one definition rule would require the linker to see
that the names are identical. Then the linker could verify that the
definitions are identical or assume that they are identical and ignore
one. However I could be completely wrong about this, so if I am someone
please correct me.

>4. Will there be issues with dependencies across shared libraries? Say
>Singleton<MyClass> depends on Singleton<Logger> because MyClass::~MyClass()
>needs to log stuff. If these are in separate libraries, won't the order in
>which the libraries are unloaded pose a problem?
>
Perhaps the lifetime of the dlls themselves could be managed with
singletons? When the dll's dtor is called, it could unregister the
relevant classes and unload the dll.

-Jason


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk