What I use where (some) other ppl use singletons.

Started by
17 comments, last by JohnBolton 18 years, 3 months ago
I have no singletons in my code. By this I mean that no objects enforce a 'one instance only' rule. However, I have several objects which de facto exist in only one globally-accessible instance (aside from their instances in the unit tests for the various modules). Moreover, they are not accessed in a naked way, but instead through a function that allows me to change the underlying object at will in unit tests, even though this never happens in practice while the game is running.

The three objects made available this way are:

  • Allocator : a pool allocator system, which is mainly accessible through operator new.

  • ContextStack : a stack of contexts, each context contains a GarbageCollector (a garbage collector that can be used to flush from memory all the objects allocated during the context when it is popped), Graphics (set of renderable objects, their positions, and the camera position) and a Clock (measures time, in seconds, since the context was pushed).

  • Resources : a resource system that loads and unloads resources based upon requests from the system.

Advertisement
Quote:Original post by Dmytry
Quote:Original post by ChaosX2
Wouldn't it be easier to just have the class instantiated once and then have a pointer to that class passed around?

it is theoretically good, but in really many cases you can not do that, and in such cases programmers usually use singletons even if they absolutely don't need "single" part.


I am a firm believer in KISS. If a singleton design pattern does not make sense and you can't pass a pointer to the object, then just define a global instance of the class and use that.
<a href="http://ruggles.hopto.org>My Personal Website
Quote:Original post by Dmytry
three words: initialization order problems. The thing that singleton is intended to solve.


no. IMPLEMENTATIONS of singletons try to solve that, but it's not a rule defined in the DEFINITION of a singleton. it's just a matter of fact that order of initialisation is always a problem. but the OP shows a solution to this wich works, and is NOT a singleton.

a singleton only forces a class to have at most only one instance. thats the ONLY thing a singleton defines and forces. the rest is a c++ thing. order of initialisation of global objects is an issue, singleton or not.
If that's not the help you're after then you're going to have to explain the problem better than what you have. - joanusdmentia

My Page davepermen.net | My Music on Bandcamp and on Soundcloud

Quote:Original post by Dmytry
three words: initialization order problems. The thing that singleton is intended to solve.
With local static, it is created when execution goes over it.


I'm not sure I understand how this solves initialization order problems, specifically since the objects are created as execution hits them. That means that your objects are created invisibly depending on the first use of the functions your macro creates.

For example, let's take two modules 'Foo' and 'Bar' that are created using your macros. If Bar HAS to be instantiated before Foo (to illustrate the problem), how would you keep track of that? Someone may unknowingly call the Foo function before Bar, creating the Foo before Bar and causing havoc. The initialization order problem is still there, but your solution (imo) makes it harder to track down which objects are created when and where since it's dependant upon execution.

Singletons or not, I'm a BIG fan of very explicit Create-Destroy / Init-Deinit construction pairs. That way I know exactly which objects / systems are created in what order, and conversely I know exactly which order they are destroyed.

Also, destruction orders are VERY important, and should never be ignored if it matters. And the worst part is, they're sometimes the hardest ones to track down / solve.

Quote:Original post by Grafalgar
I'm not sure I understand how this solves initialization order problems, specifically since the objects are created as execution hits them. That means that your objects are created invisibly depending on the first use of the functions your macro creates.

For example, let's take two modules 'Foo' and 'Bar' that are created using your macros. If Bar HAS to be instantiated before Foo (to illustrate the problem), how would you keep track of that? Someone may unknowingly call the Foo function before Bar, creating the Foo before Bar and causing havoc. The initialization order problem is still there, but your solution (imo) makes it harder to track down which objects are created when and where since it's dependant upon execution.

Singletons or not, I'm a BIG fan of very explicit Create-Destroy / Init-Deinit construction pairs. That way I know exactly which objects / systems are created in what order, and conversely I know exactly which order they are destroyed.

Also, destruction orders are VERY important, and should never be ignored if it matters. And the worst part is, they're sometimes the hardest ones to track down / solve.


this is the magic of it. if Bar has to exist before Foo, it simply gets called ala GetBar() there in teh Foo code, where Bar has to exist. that way, it will always get initialised first, no matter what the user uses first.

and if Bar and Foo call eachother recursively, the compiler should detect and inform.
If that's not the help you're after then you're going to have to explain the problem better than what you have. - joanusdmentia

My Page davepermen.net | My Music on Bandcamp and on Soundcloud

Quote:Original post by davepermen
this is the magic of it. if Bar has to exist before Foo, it simply gets called ala GetBar() there in teh Foo code, where Bar has to exist. that way, it will always get initialised first, no matter what the user uses first.

and if Bar and Foo call eachother recursively, the compiler should detect and inform.


Hmm - good point. I can see how that'll work out. I still am, in general, not comfortable with objects that get initialized at seemingly unknown times - even when it comes to singletons, I prefer to create/initialize them in a very specific spot and destroy/deinit at another spot - it helps keep things clean organized.
Quote:Original post by Grafalgar
... I prefer to create/initialize them in a very specific spot and destroy/deinit at another spot - it helps keep things clean organized.


In a complicated system, the proper order of initialization is not always easy to determine nor is it easy to maintain. How do you deal with statically allocated data?

In a system where everything is guaranteed to be initialized before it is used, you don't have to worry about the order of initialization, because it is automatic.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Quote:Original post by JohnBolton
In a complicated system, the proper order of initialization is not always easy to determine nor is it easy to maintain. How do you deal with statically allocated data?

In a system where everything is guaranteed to be initialized before it is used, you don't have to worry about the order of initialization, because it is automatic.


My statically allocated major system components don't get initialized during construction. They are initialized explicitly by the main 'overarching' system :P I don't believe in big components being initialized and whatnot as soon as they are created.

Thus, in said big and complicated system, keeping all major system components' init/deinit functions closely together really helps to maintain the code. Whenever something is 'automatic' warning flags come up for me :P
The creation-upon-first-reference technique is more than just a way to solve order-of-initialization. Consider that a "global" object is more than just global in the lexical scope, it is also global in time. That is, a truly global object is accessible from anywhere at any time. An object that exists only within the lifespan of another object is not truly global. In effect, it is a member of the object that limits its lifespan.

The the creation-upon-first-reference technique is simply a way to make an object at least appear global in time, whether it really is or not.

The word "global" in the definition of a Singleton includes being global in time, so that is why the Singleton pattern includes creation-upon-first-reference. Otherwise, the access is not truly global.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!

This topic is closed to new replies.

Advertisement