Singleton with parameter initialisation

Solution 1:

Here's a minimal Meyers-like singleton with initialisation.

class Singleton
{
  private:
    int data;
    Singleton(int d) : data(d) {};
    Singleton(const Singleton&) = delete;
    void operator=(const Singleton&) = delete;
  public:
    int getData() { return data; }

    static Singleton& instance(std::function<Singleton()> *init = nullptr) {
        static Singleton s{(*init)()};
        return s;
    }

    static void initialize(int d) {
        std::function<Singleton()> init = [d]() { return Singleton(d); };
        instance(&init);
    }
};

If you call instance without calling initialize first, it will crash on dereferencing a null pointer (of course feel free to insert asserts/checks to catch this in debug mode, or in release mode if you are so inclined).

This requires C++17; for earlier versions of the language, replace delete with default.

Solution 2:

According to C++ standard any static variable inside function's body is always protected with atomic bool (to check if it is initialized) and intialization is protected with mutex.

This makes static variable a very handy tool to create simplest yet thread safe solution for implementing Singleton concept. I do this in following 5 lines of code, together with usage of std::optional to pass initial value. Optional's method .value() throws an exception if we forget to pass init value for the first time.

As you see I made Singleton function templated so you can store any type inside and also added second optional UniqueTag param, so that you can create several singleton's out of one type.

To remind, any templated function has its own static variable instance for every instantiation of a template. So all singletons have different static variable inside.

Try it online!

#include <optional>
#include <iostream>

template <typename T, typename UnqiueTag = void>
T const & Singleton(std::optional<T> const & init = std::nullopt) {
    static T val{init.value()};
    return val;
}

int main() {
    struct First {};
    struct Second {};
    std::cout
        << Singleton<int, First>(123) << " "
        << Singleton<int, First>() << " "
        << Singleton<int, Second>(456) << " "
        << Singleton<int, Second>() << " "
        << Singleton<std::string>("Hello!") << " "
        << Singleton<std::string>() << " "
        << std::endl;
}

Output:

123 123 456 456 Hello! Hello!