Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Self-storing class-instances on creation


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 Juliean   GDNet+   -  Reputation: 2741

Like
0Likes
Like

Posted 24 August 2012 - 08:18 AM

Hello,

when having a closer look at libaries like Qt, I've noticed some of them works like this:

  1	    #include <QApplication>
  2	    #include <QTextEdit>
  3
  4	    int main(int argv, char **args)
  5	    {
  6		    QApplication app(argv, args);
  7
  8		    QTextEdit textEdit;
  9		    textEdit.show();
10
11		    return app.exec();
12	    }

So although there is no direct relation between app and textedit, app somehow knows that I created textEdit, as on calling app.exec() it will dispatch events to textEdit. How does that work? The only way I can think about is, having a static function registerWidget and a static vector<>-structure in QApplication, and in the Constructor of QTextEdit (or any widget) it calls QApplication::registerWidget(self). Is this ok to do so or is there any better way to do this? (not talking about gui-libaries but this self-storing/registering thing in general)

Sponsor:

#2 BitMaster   Crossbones+   -  Reputation: 4435

Like
2Likes
Like

Posted 24 August 2012 - 08:33 AM

There can only be one QApplication (actually a QCoreApplication) object in an application and that counts as a singleton, accessible via QCoreApplication::instance.

#3 Juliean   GDNet+   -  Reputation: 2741

Like
0Likes
Like

Posted 24 August 2012 - 08:46 AM

Isn't singleton a bad design pattern? What I've read until now always said singletons should be avoided at any cost, so this is a case where a singleton should be used, right?

#4 rip-off   Moderators   -  Reputation: 8754

Like
5Likes
Like

Posted 24 August 2012 - 09:15 AM

No, this is a case where a singleton was used. It doesn't make it right, nor does it mean it is absolutely wrong. It was a design decision by the QT team. It would be interesting to know if the team would choose this design now, were they free of any backward compatibility constraints.

Design is a subtle art, particularly when one is designing a complex public API that will be consumed by thousands of applications. The problem with singletons is that they are extremely attractive to design beginners, because they "solve" all those complex issues of lifetime and communication. Someone with design experience will realise the solution involves side stepping these important questions. This is convenient in the short term, but eventually these questions will demand an answer. Trying to retrofit a coherent answer into an existing codebase is not a trivial task.

#5 Juliean   GDNet+   -  Reputation: 2741

Like
0Likes
Like

Posted 24 August 2012 - 09:39 AM

Ok, I see that this anwser cannot be given as trivial as I thought.

But, say I want to write a small gui-libary myself. It would be only used by me, and I want it to be reusable for different projects. The main usage would be to build game-editor(s) and maybe ingame-huds. My objects need to be registered to a class that dispatches events to them, etc.. . I'd prefer having the objects automatically registered on creation. What are my options here? I see the following:

- Singleton and having the objects register themselfs (I don't really see any downside in my current design plan with this)
- A factory class that registers objects on creation
- Having to register objects manually

So uhm.. I personally like the idea of the singleton, like you said, its very tempting to me as being unexperienced with good code design. What would you suggest me to do? What pays out the most on long-term? Not specially the three cases I wrote here, I'd really like to hear about some different design patterns for this, if there are any..?

Edited by The King2, 24 August 2012 - 09:47 AM.


#6 tim_shea   Members   -  Reputation: 461

Like
2Likes
Like

Posted 24 August 2012 - 10:07 AM

One thing to keep in mind is that everything doesn't have to be an object. If some collection of functions and data is related, then it's often useful to group them together, but you should really consider whether it makes sense to create one. If clients of the gui management code will likely only use one or two methods (register, unregister?) then you don't have to wrap that functionality into an object to be instantiated, especially if doing so would require you to provide static functions anyway.
On the other hand, if you really do think there are enough operations and data to justify defining an object, and it does in fact make sense to instantiate one, then by avoiding singletons you actually gain a lot of flexibility (one lightweight gui manager handles the hud, another for the pause screen menus).
I think if you embrace the fact that a single program can incorporate multiple paradigms, you should see the need for singletons decline.

#7 Juliean   GDNet+   -  Reputation: 2741

Like
0Likes
Like

Posted 24 August 2012 - 10:55 AM

If clients of the gui management code will likely only use one or two methods (register, unregister?) then you don't have to wrap that functionality into an object to be instantiated, especially if doing so would require you to provide static functions anyway.


You are right, my clients are only going to use a fair minimum of methods, aside from register/unregister I have a method to distribute events, as well as some setter-methods for different focus situations. Since I won't need more than one manager too, I quess I really don't need an instanced object at all. So I'll go with a class providing static functions instead, this should fit my needs.

Thanks for the help :)

#8 Narf the Mouse   Members   -  Reputation: 318

Like
1Likes
Like

Posted 24 August 2012 - 03:09 PM

Globals smell, but sometimes all the alternatives stink worse.

Unless someone's solved the "log errors in app consistently" problem in a simple, concise, and non-abusable way. If it has been solved, it's never been mentioned in any thread on the issue I've seen, which, admittedly, isn't all of them.

Edit: Seriously, if it has, I'd like to know.

Edited by Narf the Mouse, 24 August 2012 - 03:10 PM.


#9 krippy2k8   Members   -  Reputation: 646

Like
3Likes
Like

Posted 24 August 2012 - 04:39 PM

What I've read until now always said singletons should be avoided at any cost, so this is a case where a singleton should be used, right?


No, you should not avoid them at any cost. You should avoid them when they would put unnecessary restrictions on your application, or the cost of avoiding them is more expensive than the cost of using them.

QCoreApplication is at it's core an interface between the application and the operating system. It does not make sense to have more than one such object in your application. It is also an object manager in that it maintains a collection of all QObjects in the application and supports sending events between them.

A case can be made that it could be useful to have more than one object manager in an application. And that is true, but having a master QCoreApplication that maintains a collection of all objects in the application does not preclude you from having separate object managers that manage distinct collections of objects. In fact QObject is itself a manager of other QObjects, so it's a trivial matter to create as many object managers or window managers as you want, while at the same time having the one master manager that can handle things like shutdown events from the operating system and then send out messages to everything else in the application to ensure that it's shut down gracefully where possible.

And perhaps more importantly in this case, having a singleton QApplication as the top level window manager helps make the Qt library more user friendly, and that is at the core of the design principles behind Qt.

#10 Codarki   Members   -  Reputation: 462

Like
1Likes
Like

Posted 25 August 2012 - 12:28 AM

- Singleton and having the objects register themselfs (I don't really see any downside in my current design plan with this)
- A factory class that registers objects on creation
- Having to register objects manually


I'll add one which I believe is more modern style RAII approach compared to other suggestions here:
- Objects register themselves to a registry, which is passed in to their constructors. And unregisters at destruction. No static objects nor static functions required.

#11 Juliean   GDNet+   -  Reputation: 2741

Like
1Likes
Like

Posted 25 August 2012 - 05:02 AM

Unless someone's solved the "log errors in app consistently" problem in a simple, concise, and non-abusable way. If it has been solved, it's never been mentioned in any thread on the issue I've seen, which, admittedly, isn't all of them.


What do you mean by "log errors in app consistensy"? How does that come into play when using globals?

And perhaps more importantly in this case, having a singleton QApplication as the top level window manager helps make the Qt library more user friendly, and that is at the core of the design principles behind Qt.


Yeah, making the libary user-friendly is important for me too. I don't want having to screw around when creating my objects too much.

I'll add one which I believe is more modern style RAII approach compared to other suggestions here:
- Objects register themselves to a registry, which is passed in to their constructors. And unregisters at destruction. No static objects nor static functions required.


Hmm yeah the only downside is that I have to pass the registry to whatever place I want to create a object. You'r talking about storing the register in the object so it can unregister on destruction, right? I wouldn't be delighted having to pass the registry every time before destructor is called..

So after all I quess a static function-class is really the way for me to go. It doesn't restrict me in my design plans, and it makes things much easier.

#12 dilyan_rusev   Members   -  Reputation: 1071

Like
0Likes
Like

Posted 26 August 2012 - 06:48 AM

If you are using C++, you can't just give up objects, because of all the memory management and exception safety "happiness". I don't really know any other sane way for managing resources other than RAII.

When it comes to singletons, I think their shortcomings are kind of exaggerated. I feel like this is one of those things that small kids are told not to do (like don't pee in your pants). Most of the time, it's just that programmers with experience that keep on preaching it's bad (cause it's one of those widely accepted things like "don't use goto") to get recognition from peers. And since everybody happily agrees, newbies don't get to have a coherent explanation as to why - they are often left with a list of "don't-s".

The singleton pattern is very useful, because it allows you to guard the access to global variables. The idea with patterns is that you shouldn't take them too seriously. They are just solutions to problems, usually making the least evil possible in a bad situation. You should, rather, take the core idea and modify it to suit your case. A slight variation of the singleton pattern is the immutable object, which is universally accepted as a good thing. Or your singleton can be unique per thread, per GUI window, per player, etc.

The worst thing about singletons is that they make your API hard to discover, since you have to know they exist. Also, they are very difficult to change. This applies not just to singletons, but to any static method that you have to know that has to be called at any point. Static methods are an abomination, IMO, but since some language authors decided that "thou shalt only have objects", it is the only way to have global functions.

About your UI dilemma - I'd suggest data-driven UI. Make up an XML or JSON schema and define your UI in it. If you are punished to use C++, you'll have to have some pure abstract class for registering actions that get invoked in the XML, so that your UI loader would be something like loadUI(fileName, callbackHandler). The callback handler would respond to any action invoked in the declarative UI by name. In languages that support metadata (or if you make UI logic as DLL plugins in C++), you'd just dynamically load the callbacks. That's how I'd do it, since I've grown to like declarative programming, I really think it allows you to experiment with UI options much more than "normal" code that has to be recompiled. And since it's data-driven, you can employ RAII and stuff as much as you want in the reader.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS