arlo on 19 Jun 2003 18:03:01 -0000


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: [ALACPP] Singleton clarification


Overall, I have to agree with Chris on the Singleton issue. This is especially
the case in C++ in Windows. We had merry hell last winter because our system
was divided into multiple DLLs. Static variables are one-per-PE-per-process,
and wre the usual low-level implementation of singletons. Thus, what we though
was one-per-process was actually one-per-DLL-per-process, and the sharing of
data didn't work out well.

We eventually solved the problem by moving all of the singletons (5 of them)
into their own DLL, and having all others use them from there. However, this
was also lame.

[snipped and re-ordered]

> So, one of the things I've tried is to have a non-static method with a
> static variable inside it:
>
> class NotASingleton {
> public:
>     SingletonClass& getSingleton() {
>         static SingletonClass instance;
>         return instance;
>     }
> };

This is a common implementation of the Monostate pattern (see
http://www.objectmentor.com/resources/articles/SingletonAndMonostate.pdf, by
Robert Martin). It does have a number of advantages over Singleton, and there
are more advanced implementations that get around some of its remaining
problems. Still, it gets complex and shows issues when you dynamically load /
unload PEs, or when you have mutually dependent monostates (and need to write
phoenix-like behavior, or something).

I generally (now) prefer monostates over singletons. For one thing, they are a
lot easier to refactor. However, all cases of global shared access to a static
variable cause problems.

That said, there are still a few cases where singletons / monostates are the
correct solution to a problem. One example is a dynamic registry of active
object instances (map from some key to object). Eg, if you have several
different groups of objects, one per network connection, and need to look up
the correct set of objects to dispatch to based only on a string / numeric
representation of the address / port.

However, as I work more and more, I find fewer and fewer reasons to use
non-constant static variables, ad with them, fewer reasons to use singletons.

> Everyone should log, but such logging takes place in a very specific
> context. log4cpp provides categories to capture that context, but
> because the fundamental system is tied to a singleton this can be a problem.

The real problem that I have with log4cpp isn't that they use singletons. It's
that they think that they're using singletons, but don't. They just use a
bunch of mutually-dependent global static variables. They don't control
ccreation or destruction order, even though the destructors for some of them
use others of them. If they at least stepped up to singletons, then they could
fix a number of their crash on close or leak on close bugs.

Singletons may be ugly, and capable of causing difficult-to-find errors, but
global static variables cause really fun problems, especially in a source
distro. Just trust that someone else's compiler will initialize and destroy
the variables in a different order.

>> When it comes to controlling access, I've messed around with inheriting
>> access; it's good when you want decentralized access control. When you
>> want centralized access control, perhaps the simplest way is something
>> like this:
>>
>> class KeyboardAccessor : private SingletonHolder< Keyboard > {
>>
>> friend class InputReader;
>> friend class EventManager;
>>
>> };
>>
>> This can be more sophisticated, to guard against the usual band of
>> pitfalls, but I like that it uses simple language constructs: access is
>> private, unless you're listed as a friend.

I've also seen a similar approach using composition or a token to define who
was allowed to do things. This had the advantage of separating the list of
friends from the object being protected, without messing with the inheritance
hierarchy. Not often necessary, but useful from time to time.

Arlo



_______________________________________________
alacpp mailing list
alacpp@xxxxxxxxxxx
http://lists.ellipsis.cx/mailman/listinfo/alacpp