How to hide a singleton
You might look at that and decide that we have simply hidden a singleton behind a function. Indeed, hiding singletons is easy and the Core Guidelines remarks that enforcing their nonuse is very hard in general. The first enforcement idea offered by this specific Core Guideline I.3: “Avoid singletons,” is “look for classes with names that include singleton.” This might seem somewhat specious, but since Singleton is one of the Design Patterns it is remarkably common for engineers to add it to the name of a class, to identify that “this is a singleton” or “I have read the Design Pat-terns book.” Of course, doing so embeds the implementation in the interface, which is A Bad Thing, but that is another topic.
The second idea offered by the guideline is “look for classes for which only a single object is created (by counting objects or by examining constructors).” This requires a complete, manual, class-by-class audit of your codebase. Sometimes singletons are created by accident. An abstraction may be inducted and a class formed from it, and all the scaffolding required to manage the life cycle of and interactions with that class may be created, such as the special functions, public interface, and so on, but only one instance of the object may ever exist at one time. It may not have been the engineer’s intention to create a singleton, but that is what has happened; a count of all the instances reveals the quantity to be one.
The final idea is “If a class X has a public static function that contains a function-local static of the class type X and returns a pointer or reference to it, ban that.” This is exactly the technique described above to resolve the static initialization order fiasco. The class may have a superset of the following interface:
class Manager { public: static Manager& instance(); private: Manager(); };
The giveaway here is the private constructor. Nothing can create this object except a static member or a friend, and we see no friend declarations. Nothing can derive from it unless another constructor is added to the nonprivate interface. The private constructor indicates that “my construction is tightly controlled by other functions in my interface” and lo! And behold! The public interface contains a static function which returns a reference to an instance. You will no doubt be able to guess the gen-eral content of this member function by looking at the manager() example function above.
A subtle variation of this is the reference-counted singleton. Consider a class that is a huge resource hog. Not only do you not want two instances of these to exist at once, but you also want it to be destroyed the moment it is no longer needed. This is somewhat complex to manage, since you need a shared pointer, a mutex, and a reference counter. However, this is still a singleton and falls under the “Avoid single-tons” guideline.
You might be looking at that public static member function and saying to yourself “surely the guideline should say ‘Avoid static storage duration objects.’ They are sin-gletons, after all.” Hold that thought.