3
\$\begingroup\$

I am sure most of my classes like for rendering text, sprite, shapes are not going to need more than one instance. Is it adequate to consider only this fact that its only going to need one instance? Should i also consider other things?

\$\endgroup\$
  • 3
    \$\begingroup\$ I think rather than saying "I only need one" you should consider singletons when "I should only have one (at most)". Just because you (currently) only need a single instance of a class does not mean it will always stay the same. However if you know that you should never have more than one instance, then it probably should be a singleton. \$\endgroup\$ – UnholySheep Dec 28 '16 at 18:48
13
\$\begingroup\$

Do you think you don't need more than one or do you think there must never be more than one?

The singleton pattern is mostly useful in situations where the existence of more than one instance of a certain class isn't just unnecessary but would actually cause bugs, so you want to avoid at all cost that there ever is a second instance of it.

Also consider the alternative to a singleton: A purely static class, which in C++ can alternatively be implemented as a namespace. This is usually far easier to use and write and results in far more readable code. The main drawback is that you can't have a pointer or reference to a namespace. But I could hardly think of a situation where you would want that and where a singleton would still make sense.

\$\endgroup\$
  • 3
    \$\begingroup\$ +1, the question author should consider: What could go wrong if I inadvertently create multiple of these instances? \$\endgroup\$ – André Dec 29 '16 at 9:58
  • \$\begingroup\$ Game Programming Patterns presents one handy use for a singleton over a static class/namespace. By using a singleton for platform-specific functionality like file system interactions, you can write a subclass for each platform, and centralize the platform-selection logic when deciding which to construct in the singleton's GetInstance method. That probably doesn't apply to the particular examples in the question - just a neat aside. \$\endgroup\$ – DMGregory Jan 2 '17 at 16:18
  • \$\begingroup\$ @GMGregory But is a file system abstraction really something which must be a singleton? You can have the same effect with a static factory method FileSystem& FileSystem::createFileSystem() which returns a PS3FileSystem on PS3 and a WiiFileSystem on Wii. \$\endgroup\$ – Philipp Jan 2 '17 at 16:58
  • \$\begingroup\$ Sorry, I didn't intend to imply that this must be a singleton. I just thought I'd chip it in as an example of a case that might fit your closing sentence, if one chose to implement it that way. \$\endgroup\$ – DMGregory Jan 2 '17 at 17:12
  • \$\begingroup\$ @DMGregory In my opinion that is an abuse of inheritance. You're going to be compiling your code separately for different platforms (because this is C++), so you should implement platform-specific logic in different files and choose which file to compile based on your build's target platform. It's unlikely that the code for a specific platform will compile on other platforms anyway. \$\endgroup\$ – Miles Rout Jan 4 '17 at 0:01
4
\$\begingroup\$

The book Game Programming Patterns (which you can read free online) has a good overview of considerations for when to use / avoid singletons.

The cautionary advice boils down to:

  • A singleton is a global variable, with all the trouble that comes with it: (this also applies to static classes)

    • Increasing the complexity of reasoning about your code, because now any two pieces of code that touch this singleton can indirectly affect each other, no matter how disparately they're separated in your code base.
    • Encouraging coupling between two systems. You probably want the SpriteRenderer.RenderSprite() method called only by your main render loop. But by putting it in a singleton, it's accessible anywhere, making it easy for a junior programmer to shortcut the intended flow of rendering and, say, try to render an impact sprite in a collision handler - now your physics and rendering are coupled, even if you had a neat messaging system that could have avoided the coupling. (We have a habit of reaching for whatever tool seems most direct, and singletons are very direct!)
    • Opening up to concurrency problems. Many modern games are multi-threaded, and a singleton is accessible to every thread, without knowledge of what the other threads are doing with it. This makes it easy to introduce bugs, or increase your code complexity with additional locks and checks.
  • Singletons solve multiple problems (convenient access, enforced uniqueness, lazy instantiation), when maybe we only needed to solve one. The extra features we didn't need can trip us up later.

    • A common problem is to implement a singleton for convenient access early in a project when you only need one, so the uniqueness isn't a problem or a feature, just an inoffensive side-effect. If later you have a use case for multiple (eg. going from a single instance of Player to a multiplayer mode) then you have a lot of refactoring on your hands. (This is in line with Philipp & UnholySheep's advice: are you sure you never want more than one?)
    • Lazy instantiation means the heavy work of constructing an instance could happen at an inopportune time in your game (eg. if you spin up your stat reporting service the first time the player picks up a collectible, it could cause a hitch in gameplay). If you know you'll need exactly one of these at all times, it might as well be a static class (or namespace as Philipp points out) so you skip any added complexity of a singleton, and your code is explicit about what's happening.

Check the article for some alternatives that may get the functionality you need without the singleton baggage. Singletons aren't necessarily bad, but the case you describe doesn't sound like one that needs a singleton solution.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.