2024-05-22

It's a Singleton for life-cycle management, maybe?

Global state has it's well known costs, so avoiding it where reasonable is a thing. Great. But sometime you might feel you need some. Then what? This article is to record some of my thoughts about the Singelton pattern in C++

Avoid singletons —C++ Core Guidelines

Which Singelton is easy

A lot of Singelton implementations are not thread safe, and/or hard to get right. The Meyer Singelton is surprisingly simple and inherits thread-safety from guarantees made by the C++-11 standard.

When to consider a singleton

Programs can need data and they can need behaviors. You might want (or think you want) either with global scope,1 but a Singelton class doesn't offer anything over a simple global variable for plain data. Nor does it offer anything over a simple free-function unless you want some persistent state attached to more than one function together.2 Either of these is simple on their own, it's only when you need the combination, behavior working on global data that Singletons offer any advantage over simple global data or free functions. So when we look at alternatives, we should be thinking about the combination.

Alternatives

Simple global data. Suffers from the static initialization order fiasco. More than a few sources suggest that an suitable alternative is to use a namespaces and just write free code. This isn't Java and things don't have to be objects.

Interestingly the Core Guidelines suggest using the same static local variable idea exploited in the Meyers singleton implementation without the object context which does not enfore the single nature, but does give you a centralized access point for a particular instance of the data.

Object Lifecycle

But here's the thing: in C++, objects are about lifecycle. They have a defined lifetime and we are guaranteed that their constructors are called at the beginning and their destructors at the end. That's how scope bounded resource management works, afterall.


1 Indeed, in the usual C++ model, almost all behavior is nominally available at global scope.

2 We'll talk about peristent state attached to a single function along the way.

No comments:

Post a Comment