Skip to main content
gamedev.net
🔒 Locked

The Singleton Class Cluster

Started by Myopic Rhino Jul 6, 2005 at 2:46 PM 44 replies 6k views
Emmanuel Deloget
Emmanuel Deloget
I don't want to be moronic or whatever. Your article is cool enough, and you don't deserve it. Nevertheless, I have to add some minor things:

1) the optimal implementation of the singleton class (the Meyer's Singleton, since Bertrand Meyer was the first to introduce it) is not optimal at all. It even have some big problems when it comes to its destructions, because you can't control the order of destruction of your singletons objects. I suggest you to re-read the "modern C++ design" by Alexandrescu, and more precisely the chapter about the Singleton. Moreover, it lacks a private desructor (one can do delete singleton->getInstance(), which is quite a bad idea, but can happen).

2) you templated singleton class defeats some of the singleton purpose. The cool thing in a singleton is that the uniqueness of the singleton is ensured at compile time, not at run time. Using your mecanism, you have to test wether it has been created or not - thus, the uniqueness is enforces at run time, wich is not the best thing to do.
The fact that a singleton is created whe you call getInstance() for the first time is actually a good thing - because you only pay for what you use, which is a rather cool concept. The main problem about singleton is their desruction. Meyer suggested its own one. Alexandrescu gave some other examples to control the life duration of a singleton. Ovbvioulsy, the fact that it is not destroyed before the program termination is actually a good thing - remember what a singleton is. A singleton exists (from a concept point off view, it is not created. It simply exists).

4) conceptually, your solution is limited because it breaks the OCP (the open-closed principle). What if you want to add a new kind of renderer (say, a Glide renderer or a xna-based renderer) ? You have to modify the base class of all your renderer classes. A base class should not know about its derived classes - even in a static function.

Now, your article earn some good points too :)

For a more complete discussion about singletons, I really suggest you to read Alexandrescu's book. His implementation is probably the best C++ implementation of a singleton out there.

Regards,
swiftcoder
swiftcoder
Yay, I am published!

I agree that as it stands, it breaks the open-closed principle, but as I mentioned in the article, if you load (for instance) renderers from DLLs, then you can have subclasses loaded dynamically, and then choose which one eityher by presenting to the user, or by bets feature match, etc.
So one can work around the breakage.

As far as the singletons go, I guess it is a matter of taste, I personally like explicit control of construction/destruction, and 'optimal' probably wasn't the best choice of wording.

Thanks for the feedback,

Tristam
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
ITGER
ITGER
You could instead use a virtual copy constructor. Although you can't template that, (since of course this is a virtual function, you don't know anything at compile time) you can define a macro to save yourself at least a little typing. Oh well.
nilkn
nilkn
I don't understand what's so bad about run-time instanciation of a singleton. The singleton design pattern has nothing to do with static initilization -- that's just a matter of personal taste. A singleton's purpose is merely to ensure a single instance of the class, and a global access point to it.

BTW, the article is nice, but unfortunately it's violation of the OCP kind of kills it for me [sad]

Anyway, good job!
swiftcoder
swiftcoder
Quote:
Original post by Emmanuel Deloget
Moreover, it lacks a private desructor (one can do delete singleton->getInstance(), which is quite a bad idea, but can happen).


That is an implementation artifact, I use it to provide scoped life time for singletons, by handing the instance to a scoped smart-pointer. This may or may not be a good idea, but it works for me.

Quote:
Original post by ITGER
you can define a macro to save yourself at least a little typing.


I do usually use a macro, but I left it out to keep the article to the point.
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
bkt
bkt
Nice article, we needed something like this because people always ask questions about Singletons on the forums! Someone also needs to write one about Monostates, but I haven't been fishing around here often, so maybe its already been done.

Why did't you do this? (this is from my code)

template Tp* ISingleton ::m_pObject=0;

That should save you the trouble of having to rewrite every line in order to have a Singleton object. Also you might want the constructors/destructors to be private and not protected--you don't want anyone deleting them on you! Great article though, and I'm just giving in my 2c.
-John "bKT" Bellone [homepage] [[email=j.bellone@flipsidesoftware.com]email[/email]]
swiftcoder
swiftcoder
Quote:
Original post by bkt
Nice article, we needed something like this because people always ask questions about Singletons on the forums!

Thanks.
Quote:
Why didn't you do this? (this is from my code)
template Tp* ISingleton ::m_pObject=0;
Wouldn't that save you the trouble in having to rewrite that line each and every time you wished to make a Singleton?

I did have that at first, but it plays hell with DLL boundaries (instantiating the singleton in every compilation unit), so I macro-d that line for every singleton. But it turns out that to play nicely with DLLs, you really have to write pass-through create() and destroy() methods in each subclass (info courtesy of the OGRE folks), which is a real pain.
Quote:
Also--is there really a need for a copy constructor, you shouldn't be copying Singleton objects. Just my 2c, great article!

It is actually a private copy-constructor, to ensure that you can't copy singleton objects (although I now realize that there is nothing to stop sub-classes writing a public copy-constructor, and thus upsetting the apple-cart).
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
fireside
fireside
Interesting article. I've been thinking about this problem and how to deal with it. It gives me a starting point for sure. One thing not mentioned was how it could be used with shared smart pointers like boost's. Would it work without any changes? Or, is something like this even necessary with boost's shared pointer?
swiftcoder
swiftcoder
Quote:
Original post by fireside
One thing not mentioned was how it could be used with shared smart pointers like boost's. Would it work without any changes? Or, is something like this even necessary with boost's shared pointer?


It should work as is, but I have not yet re-installed boost, so I can not test it. However, you do need to be aware that the shared pointer will destroy your singleton when it is done with it, so make sure to keep the shared pointer in scope for as long as you need the singleton.
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
Shannon Barber
Shannon Barber
Do you have a reference for the 'class cluster' DP?
That's just normal OOD to me, and the way singletons are suppose to work.

You've merged the singleton class and singelton-holder class into one; I don't think that's necessarily a bad thing thing do, and I don't think the result is a significant violation of LSP nor OCP. It's just a factory method tacked on.

The only thing I disagree with, is the assertion that singleton are widely used.
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
swiftcoder
swiftcoder
Quote:
Original post by Shannon Barber
Do you have a reference for the 'class cluster' DP?
That's just normal OOD to me, and the way singletons are suppose to work.

I am on holiday at the moment, so I don't have my information with me, but here is Apple's page describing them ClassClusters.html. They seem to have been developed for small-talk, to allow a single array or value type class to hold multiple types at runtime.

Quote:
The only thing I disagree with, is the assertion that singleton are widely used.

Point taken, although I seem to see them in fairly wide use in open source development.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
DigitalDelusion
DigitalDelusion
Quote:
Original post by Shannon Barber
Do you have a reference for the 'class cluster' DP?
That's just normal OOD to me, and the way singletons are suppose to work.

You've merged the singleton class and singelton-holder class into one; I don't think that's necessarily a bad thing thing do, and I don't think the result is a significant violation of LSP nor OCP. It's just a factory method tacked on.

The only thing I disagree with, is the assertion that singleton are widely used.


I would actually say that 'Class Cluster' is very similar to the GoF Bridge pattern at least as it's implemented in the article. And I think that's just a variant of the Envelop Letter / Handle Body idiom.
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
paulecoyote
paulecoyote
That article is pretty cool!

I wrote an article about thread safe singletons using templates and the such a couple of years ago on code-project.

http://www.codeproject.com/cpp/pdesingletontemplatenomfc.asp
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
swiftcoder
swiftcoder
Quote:
Original post by DigitalDelusion
at least as it's implemented in the article.

I would just like to point out that although my description of the class cluster is fairly accurate, the implementation I used to combine it with the singleton doesn't really resemble the original.

But the whole class cluster idea can be boiled down to: An abstract public superclass whose behavior is provided by any one of a group of hidden private subclasses
It may be that there is another (non-small-talk) name for this, and variants on this theme are certainly used in C++, although I haven't seen them used for runtime type generic arrays.
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
DigitalDelusion
DigitalDelusion
After reading the page my conclusion is that basicly the Class Cluster is the same thing as Handle Body / Bridge but with the added emphasis that the 'bodies' be privte classes.

Class Cluster sounds a lot cooler though ;)
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
dac
dac
Sorry, anonymous was me. forgot after static_cast

Singleton::Singleton() { my_singleon = static_cast(this); }
Calefaction
Calefaction
Hmm, class-clustering is kind of a strange thing to call that. It's simply hidden polymorphism combined with a factory pattern. It's a variation of the "interface contract" idiom at that.

But it's still a good pattern, no matter what you call it :)
Matt Holmes[ aka Calefaction ]Wildfire Games - General Programmerhttp://www.wildfiregames.com
swiftcoder
swiftcoder
Quote:
Original post by dac
Isn't it better way to initialize "my_singleton" in protected constructor rather than in public function?
Singleton::Singleton() { my_singleon = static_cast< T* >(this); }

For a pure singleton, the answer is yes, but I wasn't sure it would work with the variable subclass, on further testing it seems it would, so the answer is definitely yes.

Quote:
Original post by Digital Delusion
Class Cluster sounds a lot cooler though ;)

Quote:
Original post by Calefaction
Hmm, class-clustering is kind of a strange thing to call that.

Well, I admit I was drawn by the coolness of the name, though I am sure there is a more prosaic and descriptive name for it ;)
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
Deege
Deege
I think the pattern you are describing is the factory pattern and merging it with the singleton.

From GoF:
"Factory Method: Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses."
-----------------------------------<quote>In 1965, the Russian mathematician Alexander Kronrod said, "Chess is the Drosophila of artificial intelligence." However, computer chess has developed much as genetics might have if the geneticists had concentrated their efforts starting in 1910 on breeding racing Drosophila. We would have some science, but mainly we would have very fast fruit flies. -John McCarthy</quote>http://www.gamedeli.comhttp://www.deege.com

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.