|
||||||||||||||||||
Add Forum to Favorites | Send Topic To a Friend | View Forum FAQ | Track this topic Page: 1 2 »» |
Last Thread Next Thread ![]() |
| The Singleton Class Cluster |
|
![]() Emmanuel Deloget GDNet News Lead Member since: 8/27/2003 From: France |
||||
|
|
||||
| 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, -- Emmanuel D. [blog, in French] [blog, very bad googlized translation] [NEW: English version of teh blog! (WIP)] |
||||
|
||||
![]() swiftcoder Member since: 7/3/2003 From: Boston, MA, United States |
||||
|
|
||||
| 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 |
||||
|
||||
![]() ITGER Member since: 1/12/2005 From: USA |
||||
|
|
||||
| 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 Member since: 3/10/2005 From: Lebanon, MO, United States |
||||
|
|
||||
| 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 ![]() Anyway, good job! |
||||
|
||||
![]() swiftcoder Member since: 7/3/2003 From: Boston, MA, United States |
||||
|
|
||||
Quote: 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: I do usually use a macro, but I left it out to keep the article to the point. |
||||
|
||||
![]() bkt Member since: 3/8/2004 From: Tuckerton, NJ, United States |
||||
|
|
||||
| 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<typename Tp> Tp* ISingleton <Tp>::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] |
||||
|
||||
![]() swiftcoder Member since: 7/3/2003 From: Boston, MA, United States |
||||
|
|
||||
Quote: Thanks. Quote: 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: 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). |
||||
|
||||
![]() fireside Member since: 10/8/2003 |
||||
|
|
||||
| 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 Member since: 7/3/2003 From: Boston, MA, United States |
||||
|
|
||||
Quote: 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. |
||||
|
||||
![]() Shannon Barber Moderator Member since: 6/23/2000 From: Westland, MI, United States |
||||
|
|
||||
| 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. |
||||
|
||||
![]() swiftcoder Member since: 7/3/2003 From: Boston, MA, United States |
||||
|
|
||||
Quote: 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: Point taken, although I seem to see them in fairly wide use in open source development. |
||||
|
||||
![]() DigitalDelusion Member since: 10/4/2000 From: Sodertalje, Sweden |
||||
|
|
||||
Quote: 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. |
||||
|
||||
![]() paulecoyote Member since: 7/14/2003 From: Alton, United Kingdom |
||||
|
|
||||
| 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 |
||||
|
||||
![]() swiftcoder Member since: 7/3/2003 From: Boston, MA, United States |
||||
|
|
||||
Quote: 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. |
||||
|
||||
![]() DigitalDelusion Member since: 10/4/2000 From: Sodertalje, Sweden |
||||
|
|
||||
| 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 ;) |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| Isn't it better way to initialize "my_singleton" in protected constructor rather than in public function? Singleton::Singleton() { my_singleon = static_cast(this); } |
||||
|
||||
![]() dac Member since: 7/6/2005 From: Berlin, Germany |
||||
|
|
||||
| Sorry, anonymous was me. forgot <T *> after static_cast Singleton::Singleton() { my_singleon = static_cast<T *>(this); } |
||||
|
||||
![]() Calefaction Member since: 4/26/2004 From: Houston, USA |
||||
|
|
||||
| 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 :) |
||||
|
||||
![]() swiftcoder Member since: 7/3/2003 From: Boston, MA, United States |
||||
|
|
||||
Quote: 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: Quote: 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 ;) |
||||
|
||||
![]() Deege Member since: 5/7/2003 From: Westminster, CO, United States |
||||
|
|
||||
| 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." |
||||
|
||||
![]() Seriema Member since: 6/15/2001 From: Stockholm, Sweden |
||||
|
|
||||
| I'm tired, but I want to be sincere... I'll leave the actual argumenting to some links to Washus journal. So first: ENOUGH WITH THE F'IN SINGLETON PATTERN!! :) Renderer as a singleton? Because every single nook and corner of your engine AND game AND everything it touches might possibly want to affect the rendering somehow? That's just bad design... I know, I've used it when I started out and now I can't understand why I did... And calling your singleton optimal is a pretty big claim, that is far from the truth. As it's already been said in this thread, Modern C++ Design brings up alot of aspects of singletons that needs to be taken into considuration. I urge you Singleton loving people to do two things: 1) Try to follow the flow of an app using singletons. (To summarize, any part of the code can call any part of the code at any given time. The joy!) 2) Read Washus great writings on "Singletonitis". Part 1, 2, 3. Otherwise, congrats on getting an article published. Just know that you have poisoned the mind of ALOT of new programmers with Singletonitis. =/ Oh, and Emmanuel Deloget. The Meyers singleton I know is the one presented by Scott Meyers in More Effective C++. Not some Bertrand Meyer nor was it the one presented as the "optimal singleton", it was the first implementation showed that is the Meyers singleton. At least as far as I know... I will leave with one contradiction: I've actually found a good use for a Singleton.. when using GLUT >_< since it doesn't allow passing of _anything_ to the callback functions... hehe [ ThumbView: Adds thumbnail support for DDS, PCX, TGA and 16 other imagetypes for Windows XP Explorer. ] [ Chocolate peanuts: Brazilian recipe for home made chocolate covered peanuts. Pure coding pleasure. ] |
||||
|
||||
![]() Jingo Member since: 11/2/2003 From: Bath, United Kingdom |
||||
|
|
||||
| Am i missing something here? "Improved Singleton" does not appear to be a singleton in any shape or form. There are at least two ways to create multiple instances of the class, firstly there is nothing stopping you from calling the create function multiple times. Singleton<classtype>::create(); Singleton<classtype>* pSingletonOne = getptr(); Singleton<classtype>::create(); Singleton<classtype>* pSingletonTwo = getptr(); Secondly the constructor is only protected, so what is stopping you from just deriving a class from the singleton with a public constructor and then making multiple instances of that? class eg : Singleton<eg> { public: eg(); }; ... eg one; eg two; eg three; You now have multiple instances of your singleton class, which violates the requirements. |
||||
|
||||
![]() swiftcoder Member since: 7/3/2003 From: Boston, MA, United States |
||||||||
|
|
||||||||
Quote: If you don't like them, don't use them. Quote: I would honestly like to know your reasoning on this, maybe it would change my mind. Quote: I already said that was a poor choice of wording on my part (note my first reply). Quote: This is undoubtedly true, however, with a few adaptations, they still work very well for me. Quote: Hooray Quote: So put in a couple of c-style asserts, or throw a few exceptions, I felt it would over complicate the article if I tried to explain lines of assert or exception-handeling code. Nor can I actually say which is the best approach, I used to use asserts, but with the dynamic creation & destruction it seems exceptions are more useful. [quote] Quote:This is a genuine mistake, I could have sworn I made those private ;) |
||||||||
|
||||||||
![]() Jingo Member since: 11/2/2003 From: Bath, United Kingdom |
||||
|
|
||||
Quote: Unfortunatly you cannot make them private, as then you will not be able to derive from the object. Which is a fatal flaw in your implementation. ![]() |
||||
|
||||
|
Page: 1 2 »» All times are ET (US) ![]() |
Last Thread Next Thread ![]() |
|