Singleton

When you only need one copy of an object, such as a manager for a type or resource access point, it can reveal new requirements. Two requirements typically come out of a demand for uniqueness.

You may want to guarantee there’s never more than one for safety or security reasons. Or it may be because it makes no sense to have more than one. Uniqueness guarantees are easier to make if you use strong countermeasures.

If there’s only one, then there’s the question of how to access the only copy. How do you ensure no other part of the code accidentally creates an additional instance because it could not find the proper one?

The GoF solution is to make construction the job of the class, not an object. The suggestion is that other local instances can be created when the type itself doesn’t claim responsibility for maintaining uniqueness, even with a single global pointer to store the instance. Notice that in some languages, class objects (as opposed to object instances) are Singletons, but not all.

There are three problems which keep occurring with Singletons.

  1. Non-deterministic construction.
  2. Lack of destruction.
  3. Global shared state.

Non-deterministic construction has a two-fold effect. Something is going to be the first thing to fetch the instance. That will cause a spike in the processing at that point, but undeservedly so. My background is computer games and finding that a Singleton caused a one-off performance drop in the game when we first used it was an annoying problem, but at least I had a reasonable workaround. You commit a pointless fetch of the Singleton before you need it and then any workload is moved to that point in the program at the latest.

The second timing-related issue is one of non-deterministic creation order. If a system constructs on first use and use is based on something non-deterministic, your program will create Singletons in different orders in different executions.

Many things are non-deterministic in reality. If the object is only accessed based on data loaded and the application is multi-threaded or the system is referenced based on user input or even their reaction time, then consider the system to be created randomly.

Dynamic or lazy creation has bitten me several times, and again, it’s easy to fix by explicitly calling the getInstance of each Singleton in a known order early in the program before anything non-deterministic happens. But if both these fixes are necessary, why create on first access at all?

I prefer explicitly creating each object during the early phase and placing it in a globally accessible location.

The second main problem—the lack of destruction—presents additional issues. Usually, Singletons will not be guaranteed to destruct. Immortal objects can lead to difficulties in finding resource leaks. You need to keep track of which resources are held by Singletons and ignore them or find a way to ask them to release their grasp. But if you need to ask them to release, you may as well destroy them.

Destruction is also my preference. I like to delete all Singleton objects at the end of main in C++. This way, memory and file system managers can warn if their resources are not fully released.

The third and last main problem with Singletons is their state. A singleton is defined as a pattern of a unique object. Implicitly, some internal state could be allowed. It’s also described as having a way to access the object. In essence, the object is global because global refers to access—a global shared state.

A stateful singleton seems as dangerous as any other global variable. But without state, the Singleton could be a collection of free functions. So, realistically, the only time a Singleton is necessary is when it’s dangerous or when you really want something to look like an object.

“I am unique. No others like me. I’m a self-made object. You can find me by name alone.”