Skip to main content
GameDev.net gamedev.net
🔒 Locked

learning singletons

Started by jchmack Apr 29, 2007 at 6:10 AM 38 replies 6.5k views
Original Post
jchmack
jchmack
im trying to learn how to use singletons so i dont have to link so many of my manager classes using pointers.


class Singleton 
{
public:
static Singleton& Instance() 
{
	static Singleton theSingleton;
	return theSingleton;
}
/* more (non-static) functions here */

void Display()
{
	cout << "yay it works" << endl;
}

private:
Singleton(); // ctor hidden
Singleton(Singleton const&); // copy ctor hidden
Singleton& operator=(Singleton const&); // assign op. hidden
~Singleton(); // dtor hidden

};


void main()
{
	Singleton::Instance.Display();

	int stopper;
	cin >> stopper;
}


but im getting this error: error C2228: left of '.Display' must have class/struct/union Shouldn't Singleton::Instance.Display(); work? and call the display data? Thanks to all in advance =)
darookie
darookie
Try
Singleton::Instance().Display();

Since "Instance" is a method, you need to invoke it as such.
jchmack
jchmack
thank you for the fast reply =)

but now i get more problems:

error LNK2019: unresolved external symbol "private: __thiscall Singleton::Singleton(void)" (??0Singleton@@AAE@XZ) referenced in function "public: static class Singleton & __cdecl Singleton::Instance(void)" (?Instance@Singleton@@SAAAV1@XZ)

error LNK2019: unresolved external symbol "private: __thiscall Singleton::~Singleton(void)" (??1Singleton@@AAE@XZ) referenced in function "void __cdecl public: static class Instance & __cdecl Singleton::Instance(void)'::2'::`dynamic atexit destructor for 'theSingleton''(void)" (??__FtheSingleton@?1??Instance@Singleton@@SAAAV1@XZ@YAXXZ)

its not liking my ctor/dtor.

I'm reading that my singleton implementation will cause a memory leak (but only at startup) but it should still compile right?

[Edited by - jchmack on April 29, 2007 6:19:52 AM]
honnyjopper
honnyjopper
no you haven't actually written the function definitions for the ctor and dtor. you can solve this by changing your code to :

private:Singleton() {} // ctor hiddenSingleton(Singleton const&) {} // copy ctor hiddenSingleton& operator=(Singleton const&) {} // assign op. hidden~Singleton() {} // dtor hidden


if you don't actually want them to do anything.

if you want to declare them like this as "hidden" you must still provide the function body.
Alex
Alex
If the listing you provided is a complete list of your code, then the error is because you have a declaration for your constructor, but not a definition. Change your constructor from:

Singleton();

to

Singleton() { }

Same with the Destructor. The unresolved external error means that the linker can't find the symbol it describes. So either the function is not available, or it's not being compiled and linked with the rest of the program.

Hope this helps!
--------------------------------------------------Never tempt fate, fate has no willpower.
rip-off
rip-off
Consider not using singletons. Manager classes are frequently a sign of an ill thought out design.
darookie
darookie
Quote:
Original post by rip-off
Consider not using singletons. Manager classes are frequently a sign of an ill thought out design.

Seconded. The implications of using singletons (i.e. contruction/desctructon order, life-time management, etc.) are likely to create more problems than the "convenience" of a global variable in disguise.
jchmack
jchmack
wow flood of responses while i was sleeping.

1) why shouldn't i use singletons? Im planning to just have my root singleton have a pointer to each of my manager classes.

2) what should i do INSTEAD of singletons then?

3) What is the problem with the manager design pattern. I remember posting a thread here about better design patterns and many people recommended the manager pattern.

4) What should i do to replace my manager classes then.

so far most of my manager classes look like this:

class character
class characterMGR
{
vector characters

create()
destroy()
update()
}

they just store create and destroy the object they are managing.
Telastyn
Telastyn
Quote:
Original post by jchmack
1) why shouldn't i use singletons? Im planning to just have my root singleton have a pointer to each of my manager classes.


Because singletons constrain you to only ever having one instance of the class. Constraining your design allows you less flexibility later when you're inevitably going to have to adjust it.

Quote:

2) what should i do INSTEAD of singletons then?


Something that allows for the (semi)global access without the constraints. A simple global might suffice, setting a shared pointer to the object within other objects which need to know about it...

Quote:

3) What is the problem with the manager design pattern. I remember posting a thread here about better design patterns and many people recommended the manager pattern.


They tend to break the 'one class should solve one problem' guideline. They also have the tendency to be nothing more than a way to expose the data managed to bits of your program which maybe don't need to know about them.

Quote:

4) What should i do to replace my manager classes then.


*shrug* depends on the circumstance. Some of the create()/destroy() stuff might be better served in the character class itself or as free functions.

[IMO]
The singleton though is something to be avoided.
Crypter
Crypter
Quote:

1) why shouldn't i use singletons? Im planning to just have my root singleton have a pointer to each of my manager classes.

While I disagree that "Manager classes are bad", one should be carfull
of overusing singletons. If you only have one singleton for a class
that has no reason to have multiple instances, then it should be okay.
Just ensure you dont overdo it.

Quote:

2) what should i do INSTEAD of singletons then?

Allow multiple instances[smile]

A common class made a singleton (as an exmple) is a video/graphics class.
However, if one could create multiple video objects, it can represent
output to multple locations, such as multiple primary windows. With this
class being a singleton, you limit what this class can do.

Quote:

3) What is the problem with the manager design pattern. I remember posting a thread here about better design patterns and many people recommended the manager pattern.

I personally recommend it.

A simple example is [my] engine. Out of 80+ classes, only *one* is a singleton.
This singleton class is the engine "Core", which is the gateway into the engine.

Hope this helps;

Antheus
Antheus
Singletons can cause problems with multi-threading, can become a contested resource, or require excessive locking. And after this happens, there's not a single thing you can do.

Singletons generally shouldn't be used for non-invariants, or represent invariant state. Having dynamic state is generally bad.

Singletons make unit testing hell.

Yes, there are places where singletons can be used. There are situations where they can be useful.

But they are a grenade disguised as a candy, that everyone simply must have. Despite having a big honking sign saying: Don't do it. They simply look too good to be true.

For utilities, having a namespace with plain old functions is generally better. It also keeps you away from thinking about them as classes and not push state into them.

There is obviously some data, where it can be debated whether it's declared staically or passed through hierarchy - configuration, for example.

A configuration API/class/methods seem like perfect candidate for singletons. You load configuration once, you parse it at start, then use it as needed. Or do you? What if your configuration can change during run-time? There's a singleton, that doesn't know who read from it or why. You have no way to trigger consistent configuration update across entire system. There is no mechanism to allow you to propagate these changes.

Contrary to this, if you use RAII, you know exactly where configuration is loaded and from where, allowing you to pass new configuration, or at least have means of passing these new changes. In addition, it allows for fine-grained configuration applied to individual objects, rather than globally.

But as always, there is no definitive rule. There is no *MUST*, *ALWAYS* or *NEVER*. But if you have the option, and don't exactly understand why singletons could be a problem, it's usually better not to use tham.
LorenzoGatti
LorenzoGatti
Quote:
Original post by jchmack
1) why shouldn't i use singletons? Im planning to just have my root singleton have a pointer to each of my manager classes.
2) what should i do INSTEAD of singletons then?

You don't need singleton machinery if you simply need one instance each of your object registries.
As already noted, global variables are less convoluted, more honest and easier to use (above all, easier to initialize) than a singleton disguise.
Also, do you really need a "root" object that owns the object registries? Such a class seems devoid of meaningful behaviour and completely unlikely to need polymorphism and multiple instances.
Quote:

3) What is the problem with the manager design pattern. I remember posting a thread here about better design patterns and many people recommended the manager pattern.
4) What should i do to replace my manager classes then.
...
they just store create and destroy the object they are managing.

They seem to be object registries with the responsibility of owning objects; "manager" is a meaningless name, but the classes could be useful.
Telastyn doesn't like them for sensible general reasons, but maybe they are right for your design; many questions should be answered to make a convincing point that object registries are useful:
- What are the f*****g parameters and return types of the create, destroy, update methods? Do you have a problem with exactly quoted and syntactically correct code examples?
I don't like being hostile, but your level of vagueness is disrespectful.
- If objects live in a Vector, how do you deal with copies and pointers?
- Do you need to iterate through all objects of a certain type? Is the Vector, or some of its iterators, accessible by client code?
- Why should an "update" of an object interact with the object registry and not only with the individual object?
- What is the useful purpose of asking the object registry to "destroy" an object rather than directly destroying it (auto_ptr, stack variables, operator delete, etc.)? If any client is free to call this destroy method, the registry can exercise very little control.
- Why is the object registry responsible for object creation? If there are the expected factories, loading/saving mechanisms, etc. the object registry would practically offer wide open creation methods, again with very little room for policy, to be able to satisfy every client need.
- How are objects identified for the purpose of the "update" and "destroy" methods and in the code that uses them?



Omae Wa Mou Shindeiru
Emmanuel Deloget
Emmanuel Deloget
Quote:
Original post by jchmack
wow flood of responses while i was sleeping.

1) why shouldn't i use singletons? Im planning to just have my root singleton have a pointer to each of my manager classes.

2) what should i do INSTEAD of singletons then?

3) What is the problem with the manager design pattern. I remember posting a thread here about better design patterns and many people recommended the manager pattern.

4) What should i do to replace my manager classes then.

so far most of my manager classes look like this:

class character
class characterMGR
{
vector characters

create()
destroy()
update()
}

they just store create and destroy the object they are managing.


IMHO, manager classes don't exist. Well, that opinion is a direct consequence of the single responsability principle (google for more info), which states that a class should have one one reason for which it should be modified. Manager classes are often doing too much - they often create, track, destroy, update a collection of similar items. The problem is that some of these actions may have a direct influence on the other actions - meaning that a modification in create() for example, might induce a modification in update, even if create() or update() seems to be unrelated.

Whenever I see a manager class, I try to restrict its responsabilities, and I also try to find a better name for the new classes I create from this manager class. If it handles a collection of object, then Collection is a good name (although not very descriptive), If it create or destroy objects, then Factory is a good name (that means that I extend the factory meaning so that it also includes destruction of the created instances; that's not that strange in the end, but maybe a better name can be found).

Usually, I end up with a factory, a collection and a bunch of visitors.

class character_factory{public:  character *create();  // no need to destroy characters here: it's enough to delete them};class character_visitor{public:  virtual void visit(character *) = 0;};class character_collection{public:  void add(character *);  void remove(character *);  void visit(character_visitor& visitor);};


I can then create whatever visitor I want (for exemple, an updater)

class character_updater : public character_visitor{private:  // this function does what characterMGR::update() was doing  void update(character *);public:  virtual void visit(character *c)  {    update(c);  }};

Of course, the first conclusion is that the update can't modify the collection - only individual bits in the collection.

This can be handled using a remove_if method in the collection object:
class character_collection{  std::vector<character *> collection;  struct deleter  {    void operator()(character *c) [ delete c; }  };public:  void add(character *);  void remove(character *);  void visit(character_visitor& visitor);  template <FUNCTOR> void remove_if(FUNCTOR& functor)  {    std::vector<character *>::iterator new_end;    new_end = std::remove_if(collection.begin(), collection.end(), functor);    // delete all items between new_end and collection.end()    std::for_each(new_end, collection.end(), deleter());    // then erase them fron the vector    collection.erase(new_end, collection.end());  }};

OK, this sound a bit convoluted (thanks to all this template stuff and functors (so, in the end, thanks to the language itself...)). But at least that's pretty clear: the collection handles the list of characters, the factory simply creates the cheracters, and the visitors are used to iterate on this character list. Responsabilities are now completely separated - and the code is (if you remove the remove_if() stuff [smile]) a lot more maintanable (the remove_if itslef is not really complex if you have a good understanding of the standard c++ library).

HTH,
romer
romer
Quote:
Original post by Crypter
Quote:

3) What is the problem with the manager design pattern. I remember posting a thread here about better design patterns and many people recommended the manager pattern.

I personally recommend it.

A simple example is [my] engine. Out of 80+ classes, only *one* is a singleton.
This singleton class is the engine "Core", which is the gateway into the engine.

Hope this helps;


I do pretty much a similar thing. I built my engine using a service-oriented architecture approach, and every major subsystem abstracted as independent services with which you can register with a kernel object and make available to the game. The kernel is the gateway through which everything else can access currently registered services and spawn work processes, and as such, there is ever only one instance of the currently running engine (the combination of the current kernel, services, and processes). If I were to be more precise, I would have to say that the kernel is really a monostate rather than a singleton, and that there's only ever one state in which the engine can be.

My take on the whole singleton thing is that like other constructs and paradigms, it's possible to abuse them, some easier than others. Singletons just seem to be more easily abused than most, and there's empirical evidence to show that in a large chunk of the cases where they were initially used they either had to be reworked, hacked, or removed completely as requirements changed over the course of development.

I guess my personal gripe about them is that it's rather easy to write a singleton class (in C++) that either doesn't solve the initialization issue or restricts you in the sense that derived classes break singleton functionality. I believe I've seen only one example of a flexible and correctly implemented singleton shown by Scott Bilas' "An Automatic Singleton Utility", but then again I never really delved into the topic since I've never seen a need for a singleton in any of the code that I've written.
jchmack
jchmack
That is the article that made me want to use the singleton structure. I found it in game programming gems. But i believe that everyone here believe that i am planning to use singletons much more extensively than I really am. I am planning to use ONE singleton to store pointers to my manager classes... thats it. Right now i have many managers which need pointers to many other managers which is really messy. I figured i could use a singleton to hold pointers to each of my managers. Sorry for any confusion... And i guess im really sorry for being vague with my code example. I was just giving a quick example lol.
Sneftel
Sneftel
The difference between "one singleton pointing to many objects" and "many singletons each pointing to one object", at least in the way you intend to use it, is very small. Having ten singletons is not necessarily worse than having one singleton. In fact, due to encapsulation it's probably better.
jchmack
jchmack
hmm so would you recommend to make these pointers global instead or just do what i have been doing and pass the pointers manually?
Sneftel
Sneftel
If you feel confident that you can implement a good object-oriented design with proper application of the Law of Demeter, pass pointers around. Otherwise, make them global.
Antheus
Antheus
Quote:
Original post by Sneftel
If you feel confident that you can implement a good object-oriented design with proper application of the Law of Demeter, pass pointers around. Otherwise, make them global.


I'd say this is an important issue when determining which to use.

Abuse of singletons happens usually like this: "I have 17 big systems which need to talk to each other, but I don't know how. I'll just make each of them static, so each one can access each one."

The problem isn't in use of static or singleton objects. It's in using a hammer to nail a sqare peg into round hole. Hammers are a fine tool. But they can be abused.

Another problem is that singletons are often perceived as solution to problem of static variables/#defines. Where in fact, they are a hammer used instead of rock. But they are still used to pound things into places, just a more elegant one.

For loose coupling, message passing/signal/slot will usually be better. Despite giving the ability to be completely loosely coupled, it still allows adequate separation of functionality by limiting the scope to one single interaction at a time, naturally discouraging sequential access, or any other notion of implied order or dependency.
Sneftel
Sneftel
Quote:
Original post by Antheus
For loose coupling, message passing/signal/slot will usually be better. Despite giving the ability to be completely loosely coupled, it still allows adequate separation of functionality by limiting the scope to one single interaction at a time, naturally discouraging sequential access, or any other notion of implied order or dependency.

I agree for the most part... but just as singletons are often abused to "replace" globals, so are signals sometimes abused to "replace" strong coupling. This is particularly the case when the modules between which messages are passed are implemented without an exact or coherent idea as to where the lines between them are drawn. As always, there's no substitute for a well-vetted design.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.