QickGUIManager Singleton & new?

paiden

19-08-2007 17:15:46

A Simple Question.

QuickGUIManager is impemented as a Singleton. But in the Demo-Application a manager is instantiated the followng way:

QuickGUIManager* manager = new QuickGUIManager(window->sizeX, ...).


But why do i need to do that?

Normally i would use a singleton this way:

QuickGUIManager* manager = QuickGUIManager::Instance().getInstancePtr();


The question now is, what happens if i do the following

manager1 = new QuickGUIManager(...);
manager2 = new QuickGUIManager(...);


For myself, it is a little bit confusing to instantiate singletons with new, because most singletons forbid external instantiation.

Will i have 2 different GUIManager's even if GUIManager is a singleton or what?

kungfoomasta

19-08-2007 20:28:39

I am new to Singleton's, basically I tried to imitate Ogre Singletons.. apparently I didn't do it correctly. I will look up how Ogre singleton classes are created.

According to your example, there is a funcation called "Instance". What exactly does that function do? How is "getInstancePtr()" different than "getSingletonPtr()"?

I haven't tried making a second GUIManager, so I don't know what behavior will result.

paiden

19-08-2007 23:14:45


According to your example, there is a funcation called "Instance". What exactly does that function do? How is "getInstancePtr()" different than "getSingletonPtr()"?


It returns a Reference instead of a Pointer to itself. getInstancePtr() and getSingletonPtr() are the same thing.

I looked a little bit into the code of QuickGUI and I found some really weird things.

You derive from Ogre::Singleton. Ogre::Singleton already defines the Methods getSingleton() and getSingletonPtr() so why do you redefine this methods in QuickGUIManager?
I think this leads to an assertion i always get when i call getSingleton:

GUIManager& GUIManager::getSingleton(void) { assert( ms_Singleton ); return (*ms_Singleton); }


And that line makes no sense to me

template<> QuickGUI::GUIManager* Ogre::Singleton<QuickGUI::GUIManager>::ms_Singleton = 0;
i especially mean the template<>


And the Ogre singleton itself isn't a "good" singleton implementation in my opinion. It's constructor is public, and a Singleton should never have public constructors. A singleton should not be instantiateable externally because this can lead to misunderstandings.

A good imiplementation of a singleton e.g. is contained in the design-patterns library Loki.

I would recommend, that you use a simple Meyers singleton. It is really easy to understand, and works well in most cases (only mutlithreading and things like that, can lead to problems).

Regards Phil

kungfoomasta

20-08-2007 00:39:43

Thanks for the information, its true I don't understand how Singleton's work. :oops:

I did a 5 second google search, and will take the same approach outlined by this link:

http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton-Pattern-Part-I/4/

The changes will be in the v0.9.6 release. :)

Thanks again.

kungfoomasta

20-08-2007 01:59:09

Alright, so I switched over to using Instance and getInstancePtr functions for both the GUIManager and MouseCursor class. I also added the functions setup and shutdown, which for the GUIManager, need to be called by the user. The demo has also been updated to use this code. On the plus side, users cannot destroy or create more than one of these classes. :)

I also ran into a bug I had with the MouseCursor which is now fixed. (int vs Real problem)

Game_Ender

20-08-2007 03:03:34

The Ogre Singleton pattern is different and it exists to solve several limitations of the "Meyers" singleton:
* You can't pass arguments to the constructor of the Singleton
* You can't control the shutdown order of the Singletons

Also:
* The "template<> QuickGUI::GUIManager* Ogre::Singleton<QuickGUI::GUIManager>::ms_Singleton = 0;" is required for standards conforming C++ code. You need to supply a default value for the ms_Singleton static pointer, and the only way to do that is to assign it a value in a .cpp file. Failure to do this results in a link error
* The "getSingleton" methods are reimplemented because I have been told it the all template functions don't play well with shared libraries if you don't at least define them in a single C++ file.
* The constructor immediately asserts if you try to create more than one object so it enforce the singleton requirement.

I have not looked at the code but if Ogre Singleton pattern was implemented properly there is no way to use it improperly.

kungfoomasta

20-08-2007 03:37:42


* You can't pass arguments to the constructor of the Singleton
* You can't control the shutdown order of the Singletons


I also realized this, which made me create a setup/shutdown function. The benefit is that you could do something like shutdown, shutdown Ogre, re init Ogre, setup the GUIManager again. (Or similar situations)

Right now I'm leaning towards the Meyer method with setup/shutdown functions, and changing "Instance"/"getInstancePtr" to "getSingleton"/"getSingletonPtr" so it is consistent with Ogre Singletons.

Instead of "new GUIManager" and "delete mGUIManager" we have "mGUIManager->setup(...)" and "mGUIManager->shutdown()".

Unless there are additional limitations of the Meyer implementation...

Game_Ender

20-08-2007 05:24:43

Now you run the problem of someone doing the following:

// First GUIManager call
GUIManager()::getInstance().someFunction()

Where "someFunction" depends on the state set by the "setup" function, this would force a check in every function that depends on that state, or else have odd crahes. Its not the end of the world, but just more work on your part.

With Ogre's singleton pattern the one thing it doesn't guard against is a "delete getSingletonPtr()" being called where it should be. All the other errors, like "getSingletonPtr" before "newing" it "newing" it more than once,

A safe alternative would be to use your own singleton pattern which is just like Ogre's be removes the "getSingletonPtr" option for additional safety. You could also get rid of the singleton. Is there really a reason there can be only one of them?

An example this is OIS which shifted from a singleton "InputManager" to a factory function that lets you create as many as possible.

Of course with a little bit of documentation reading no user of your library should have much trouble with either setup,

EDIT: In C++ its customary to use the destructor and constructor to handle initialization more cleanly, its called Resource Acquisition Is Initialization.

paiden

20-08-2007 08:27:33


The Ogre Singleton pattern is different and it exists to solve several limitations of the "Meyers" singleton:
* You can't pass arguments to the constructor of the Singleton
* You can't control the shutdown order of the Singletons

I think the way it's implemented in Ogre is only some kind of hack. You can read nearly everything about singletons on the web and you nearly always will read, that the constructor, copyconstructor and assignment operator of a singleton are declared private or protected.



* The "getSingleton" methods are reimplemented because I have been told it the all template functions don't play well with shared libraries if you don't at least define them in a single C++ file.

I've never heard of something like that before. And it makes no sense to me. Templates are completely declared and defined in Header files. They are included in your client application. Becuase they are Templates, the will get compiled, when your client application, gets compiled. So i don't see why there should be any shared library problems. But maybe I'm wrong. So please tell me more about this problem.

Game_Ender

20-08-2007 21:15:01


I think the way it's implemented in Ogre is only some kind of hack. You can read nearly everything about singletons on the web and you nearly always will read, that the constructor, copyconstructor and assignment operator of a singleton are declared private or protected.


Well the singleton pattern is probably over used in Ogre but I wouldn't call it a hack. After all Scott Myers does argue against two step initialization which is exactly what you need to do if you don't expose the constructor and implicitly create it on the first call to acquire it.

Do a search in the Ogre "Back To Basics" forum and you should find several discussions on how to use Ogre's singleton class. They should cover the shared library issue I talked about. I am not sure its right, but its worth looking up.