Is it practical to have two instance of a Game class object

Started by
8 comments, last by Hodgman 10 years, 2 months ago

In my game, my Game class is not a singleton class so it is possible to have more than one instance of Game class running. But I have no idea if in other games where there is a reason to have more than one instance of a Game class object running.

Advertisement

If you don't want more than one instance of your Game class, then don't create more than one. There is no need to make it a singleton.

Whether it's practical to have more than one Game object instance or not would depend on its implementation, but it's unlikely to be a useful feature.

Yeah. Like Dave Hunt said, if you only need one, just make one. Sometimes is not good to over think things. Singletons add more unnessary complexity that goes beyond just saying there can only be one. You'll also be giving global access to the object which can cause problems down the line as ownership and the interactions won't be clear.

There may be a reason to run 2 instances at once if the app wants to run 2 simultaneous simulations, but it depends on the needs of the needs of the app.

Learn all about my current projects and watch some of the game development videos that I've made.

Squared Programming Home

New Personal Journal

Plausible use cases:

  • A "main" Game in an idle/paused state and an unrelated AI-only Game used as an "attract mode" demonstration or as a screen saver.
  • Multithreaded simulations of many running Games sharing read-only data, for example to validate levels or train AI players.

Omae Wa Mou Shindeiru

Another use case one could imagine would be split-screen games for two players. In that case, each "game" object would refer to the complete game experience for one player (not "the game") as such. In one-player mode, you'd put one game object into the "container" object, in two-player mode, you'd have two.

As for singletons, although most of their problems can be worked around, I'm with Dave Hunt. Creating exactly one of something if you want exactly one is simple and straightforward, so why waste your time implementing something complicated for the same effect. Singletons are easy to implement and use, and easy to implement and use wrong (though at least one annoying threading issue is solved by C++11 -- albeit I think the wrong way around: rather than making initialization thread-safe one should simply spawn additional threads later, which avoids the initialization problem in the first place).

Either way, there are cases where singletons are truly useful, but they're few. In most cases, you can do without them, and easier.

You might want to have two Game objects with slightly different configurations so you can test that their states don't diverge. Or you might end up writing a server for your game that can keep track of several Games at the same time.

Even if you can't think of a scenario where you might want more than one Game instance, keep the possibility open.


Even if you can't think of a scenario where you might want more than one Game instance, keep the possibility open.

This! Don't prevent yourself from making additional instances because you can't currently think of reasons you might need them; prevent yourself from making additional instances if you think of reasons it would be bad to do so. By not imposing an unnecessary restriction on your code now you allow yourself greater flexibility if you find the need for an additional instance in the future.

A singleton is appropriate if it would be an error for more than one instance to exist and you need global access. If you only need one of those or if they aren't strict requirements there's probably a less restrictive solution than a singleton. smile.png

- Jason Astle-Adams


if it would be an error for more than one instance to exist and you need global access

In my personal opinion, those two prerequisites rarely ever occur, and even less likely together. First of all, when would it ever really be an error if two class instances exist? As already stated before often programmers mistake "I don't need two instances" with "there absolutely should never be more than one instance", and other than that, I can't see any reason why creating two instances of any class in a game could be harmfull. If one puts at least a little thought into his class design, this would never ever be the case, because each class would probably be designed so that it takes an input (in the constructor and in its output) and generates a meaningful output (via different methods), while maintaining a certain encapsulated state. So unless you are clustering your classes with the usage of global state, then it really should not matter whether zero, one, or 200 instances of any given class exists.

Also, regarding the global state, when do you really need global state? Most programmers, for example recently in my university, use global state (i.e. singleton) just to spare them the "overhead" of passing some classes down other classes constructors (Dependency injection). There is no real need for it to be global - it was used for convenience of writing less code, just as it might seem to be convenient to use little but huge classes, make a lot of state public, and so on... yeah, you should keep your programs simple and don't overcomplicate your program (K.I.S.S), but global state rarely helps that, and more likely produces a cluttered mess where all the sudden a lot of classes need to be singletons, because they depend on one or more other singletons and can therefore not be used in isolation with more than one instances (so in a way, using singletons can cause the need to use more singletons, if that makes any sense).

I felt to give my two cents because as I said I just recently experienced how singleton was misused by almost all my collegues in their projects, creating just what the OP asked for - a "game" class singleton that was used all over the project, being an unawful god-class to add in some cases too. I'm really annoyed that singleton is being taught with so little caution and still praised as being a good (if not the most useful) pattern, IMHO it should be taught as a anti-pattern, which it is in my opinion. There are one or two uses (thread pool, logger), buts you could also use a static class or free functions for that.

So, for the OP, no, don't make it a singleton under any circumstance, keep yourself open for the possibility to create more than one instance, and certainly don't make your "game" class globally accesible. Use dependency injection to hand it around the classes that need it, or even better, have it manage some sub-systems that you pass around instead of making it an almight god-class.

mistake "I don't need two instances" with "there absolutely should never be more than one instance"

But that is the exact difference between a singleton and a single instance. A singleton must not, cannot exist with two instances. It's the reason why proper applications of singleton are so rare, too. Usually it doesn't hurt.

I can't see any reason why creating two instances of any class in a game could be harmful

Example:


class savegame_manager // loads last game session and saves it at program exit
{
	int fd;
	// ...
public:

	savegame_manager() : fd(open("blah"...)) { while(...) { read(...); set_gamestate(...); } }
	~savegame_manager() { ftruncate(fd, 0); for(...) write(...); }
};

Create two instances of these, and the second will overwrite the first one's save in its destructor. Or rather, since order of destruction is the inverse order of creation, the first will overwrite the second. See how I already got things wrong once in only two lines of text.

Or, if they run on different threads, something else will happen, likely corruption. If only the complete file is written twice, this is relatively "harmless" (assuming no exceptional condition happens in between), but it is nevertheless an error.

The example works with anything that opens files, creates render contexts, owns some resource, and so on. This very design (only with a different class name) has once upon a time been a source of many WTFs on a well-known open-source IDE where under some obscure conditions, the complete configuration would get lost. Which was of course totally impossible, but it still happened.

Create two objects that own the same handle and close it in the destructors. That'll generate an exception if a debugger is attached (it's harmless otherwise, but that is coincidence, try the same with calling free twice on the same memory address). Or create two objects that own/manage/modify the same whatever without anyone being aware of it (and thus without proper synchronization).

Recipe for desaster. And what's worst, it doesn't just go wrong -- it evidently goes wrong when actually it can't go wrong at all.


Create two objects that own the same handle and close it in the destructors. That'll generate an exception if a debugger is attached (it's harmless otherwise, but that is coincidence, try the same with calling free twice on the same memory address). Or create two objects that own/manage/modify the same whatever without anyone being aware of it (and thus without proper synchronization).

Recipe for desaster. And what's worst, it doesn't just go wrong -- it evidently goes wrong when actually it can't go wrong at all.

I see where you are going for, but thats kind of what I was talking about. In your example, I'd have it like this:


class savegame_manager // loads last game session and saves it at program exit
{
    int fd;
    // ...
public:

    savegame_manager(const std::wstring& stFilename) : fd(open(stFilename.c_str(), ...)) { while(...) { read(...); set_gamestate(...); } }
    ~savegame_manager() { ftruncate(fd, 0); for(...) write(...); }
};

That way, you can specify which file to load, and having more than one instance is now not necessarly harmful, unless you specify the same file two times, but that was your fault as the user. You could have a private static map to check whether a file is already loaded, e.g. As I said, a logger with a certain hard-coded file handle can be useful, but for a savegame-manager as in your example, its much more practical IMHO to being able to specify which file to use, which pretty much nullifies the necessity of a singleton. I get what you are saying though, but I hope you also see where I'm getting at it, there is probably always a better option than having a singleton.

This topic is closed to new replies.

Advertisement