🔒 Locked
Main Application class as singleton
Advertisement
Original Post
In the last chapters of the book Focus on SDL, the author makes a simple, yet complete (at least for simple 2D games/apps) application framework. The main class, called Application, is implemented using the singleton pattern. The main() function (hidden inside the framework code, in Application.cpp) simply calls Application's execute() method to actually start the game. The default implementation of Application does absolutely nothing. The framework relies on the fact that you define a subclass to Application and put your game-specific code in it. The book also states that you need to declare an instance of this subclass in the file implementing this subclass, which is somewhat logical, since you need to "tell your program" to use this subclass, and not the default implementation. The problem here is that to be able to instantiate the subclass, you need to make its constructor public; doesn't that destroy the "protection" provided by the singleton pattern? Nothing prevents us from instantiating it elsewhere in the code, except a simple check in the Application::setInstance() private method (used by Application's constructor). Is using a singleton as a main application class in a framework a good idea? I presume that these "problems" are at least an indication that a better solution surely exists, but what would that alternative be? Thanks in advance.
I point you toward:
Promit's journal regarding Singletons. This has the necessary links for using, misusing, and misconceptions about the singleton pattern that are very important.
Read carefully.
Promit's journal regarding Singletons. This has the necessary links for using, misusing, and misconceptions about the singleton pattern that are very important.
Read carefully.
These are my thoughts on the matter.
Quote:
Is using a singleton as a main application class in a framework a good idea? I presume that these "problems" are at least an indication that a better solution surely exists, but what would that alternative be?
Where is the problem in the first place?
Why should there be a better solution to a problem that's not a problem?
Why must an application be a singleton? Is there an advantage to be gained from limiting it to one single instance, with no life-cycle management?
Why not start 5 Applications from same executable? Hopefully you're not proposing that GUI is so tied into application that that would be impossible.
Quote:
The problem here is that to be able to instantiate the subclass, you need to make its constructor public
What about "protected"? And while I don't know the details, why does there need to be setInstance method? This smells like someone used singletons, then ran into a problems due to restrictions, and worked around them.
There are also much better template based singleton solutions which are actually singletons.
There is no "right" or "wrong" way to design an application. But at the same time - is there any need whatsoever for Application to be singleton?
Quote:
Where is the problem in the first place?
Well, the fact that the subclass' constructor is public sounds like a problem to me. Nothing prevents us from instantiation the class more than once, which is supposed to be the reason to use a singleton in the first place, no?
Quote:
Why must an application be a singleton? Is there an advantage to be gained from limiting it to one single instance, with no life-cycle management?
In the context of a game or an application (which is what that framework was made for), I feel it's logical to have one and only one instance of Application. However, I'm not sure if the singleton pattern is the best choice here; I just don't know what else could/should be used.
Quote:
What about "protected"? And while I don't know the details, why does there need to be setInstance method? This smells like someone used singletons, then ran into a problems due to restrictions, and worked around them.
That's exactly one of the "problems" I was referring to earlier; quick and dirty hacks. Here is how it was implemented in the book :
// ---------------// Application.cpp// ---------------// [...]void CApplication::SetApplication(CApplication* pTheApp){ if(s_pTheApplication!=NULL) { fprintf(stderr,"More than one CApplication created!\n"); exit(1); } s_pTheApplication=pTheApp;}CApplication::CApplication():CMessageHandler(NULL){ SetApplication(this); if(SDL_Init(SDL_INIT_EVERYTHING)==-1) { fprintf(stderr,"Failed to Init SDL:%s\n",SDL_GetError()); exit(1); } atexit(SDL_Quit);}// [...]And then in TestApplication.cpp :
// Implementation of TestApplication's methods...// [...]//declare application variableCTestApplication TheApp;Quote:
There is no "right" or "wrong" way to design an application. But at the same time - is there any need whatsoever for Application to be singleton?
That's actually what my question was in my first post; is there a better solution, if yes then what would that be. Sorry if I didn't make myself clear.
What if I wanted to subclass Application to define the behavior specific to my game? Souldn't main() also be "hidden" inside the framework? Then how could I "tell" the compiler to use my subclass? (other than doing main(...) { MyApplication myApp; myApp.run(); }, which obviously isn't an acceptable solution)
Quote:
Original post by XezekielX
Souldn't main() also be "hidden" inside the framework?
Should it? Depends on your preferences.
Personally, I'd hate it.
If I'm writing a game using your program, then I expect to write an application that uses the functionality you expose in your library.
I don't expect it to be the other way around.
I don't expect to run your application, and then have to wait for *it* to ask me what I'd like to do next.
The thing is, if I'm a C++ programmer, I already know how to write a main function, and I know that is where execution starts. If I don't have one of those, I have to start digging through documentation just to figure out *which code is actually executed*
I hate libraries that try to tell me how to work. A good library just gives you a bunch of functions and classes you can use and stick together any way you like. It doesn't try to take over the entire program. But hey, that's just my opinion.
Quote:
Then how could I "tell" the compiler to use my subclass? (other than doing main(...) { MyApplication myApp; myApp.run(); }, which obviously isn't an acceptable solution)
Why isn't that an acceptable solution?
If I'm the one starting your application framework, I presumably know exactly which particular implementation (subclass) of it I want to run. Don't I?
In fact, I'd even be skeptical of the need to have an application class at all. What needs to be encapsulated there that couldn't just as well go in the main function (or a helper function called from it)? Why does it have to be a class? Who else needs to access it?
Quote:
Original post by Spoonbender Quote:
Original post by XezekielX
Souldn't main() also be "hidden" inside the framework?
Should it? Depends on your preferences.
Personally, I'd hate it.
If I'm writing a game using your program, then I expect to write an application that uses the functionality you expose in your library.
I don't expect it to be the other way around.
I don't expect to run your application, and then have to wait for *it* to ask me what I'd like to do next.
The thing is, if I'm a C++ programmer, I already know how to write a main function, and I know that is where execution starts. If I don't have one of those, I have to start digging through documentation just to figure out *which code is actually executed*
Ok, that's a quite valid reason to not put main() in the framework. However, it simply forget to consider that a framework might need to be initialized - for example: create a memory pool, and so on. If you ask the programmer to write this code for you - or, more simply, to call the framework functions in a specific order, he's not going to be happy happy. If you push the reasoning a bit further, main() is called by the entry point of the software. Why don't we code this entry point?
Now, consider quake mods: the engine runs as an exe, and the game is a dll. We simply changed the scale, but the idea is quite similar. Nothing's wrong in considering that an application class instance is the complete application. It leaves the burden of the framework init to the framework itself, which can't be bad.
You can also give a look to the MFC - WinMain() is implemented in the framework, and when you see how complex it is, that's a pretty good thing [smile].
@OP: I can think of 2 ways to perform that:
class application // base class for all applications{ // we are going to store a pointer to the user application // object in a hidden global variable static application* the_app;public: // gives access to the user application object static application& get_app() { return *the_app; } // construct the app object application() { // don't forget to initialize the hidden application variable the_app = this; }};// in main:int main(){ application& app = application::get_app(); app.run();}Or, using a way which is quite similar to Spoonbender's view:
// first, the main function - which is in the framework#undef mainint main(int ac, const char* av[]){ framework::do_init(); // call the main() writtent by the programmer: framework_main(ac, av); framework::do_uninit();}// the user code#include "framework.h" // contains #define main framework_mainint main(int ac, const char* av[]){ my_application app; app.run();}Second solution is possible only if the framework init doesn't result in values that need to be used by the constructed application instance (otherwise you will have to modify the parameters for function main() (which is of course possible).
Best regards,
Quote:
Original post by Emmanuel Deloget
You can also give a look to the MFC - WinMain() is implemented in the framework, and when you see how complex it is, that's a pretty good thing [smile].
Considering that MFC is a steaming pile of crap, that's actually a counter-argument. [smile]
First of all, in my opinion, there is no good reason to use a singleton. Ever. It's not a design pattern, really - a design pattern is a template for a solution that can be used in multiple situations, whereas singleton is a finished piece of code that does only one thing. It's not adaptable, it's not flexible... the most "innovative" thing anyone has tried to do with singleton in the 13 years since it became popular is to create the Local Singleton.
More importantly, the library-vs-framework approach is a very critical decision. Code being written in C++ is far more likely to require or benefit from a library approach, because such code is far more likely to be integrating multiple libraries. Once you've written your monolithic framework, client C++ code can't easily integrate functionality from other sources. Bad. Code written in a higher level language (Lua, JavaScript, Python) that ties into the infrastructural C++ virtually requires an existing framework, so that's the appropriate level of granularity at that point.
Having opined, however, I shall now answer the OP's original question:
Quote:
Original post by XezekielX
The problem here is that to be able to instantiate the subclass, you need to make its constructor public; doesn't that destroy the "protection" provided by the singleton pattern?
The classic singleton is implemented as follows:
class Singleton{public: Singleton * getInstance();private: Singleton(); Singleton(Singleton *); static Singleton * instance;};An inheritable singleton will make getInstance() and the destructor, at minimum, virtual and the instance member protected. That means that your inherited singleton can do the following:
class MyApplication : public Application{public: virtual MyApplication * getInstance() { if(instance) return instance; return new MyApplication(); }private: MyApplication(); MyApplication(MyApplication *);};So the answer to your question is no, you don't need to make the constructor public and you don't need to declare an instance in the subclass. The problem is that the author botched the implementation of his Application class.
(Once again illustrating why singleton is a bad "pattern" - people don't even know how to apply it, despite their overeagerness to apply it. It's so simple it gives them delusions of software design sophistication.)
Here endeth the lesson. Blessed be Saint Oluseyi. [smile]
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement