4

I work in a project where Singletons are usually implemented like this:

class Singleton { public: static Singleton& get(); virtual ~Singleton() = default; // Used for unit tests static void reset(); protected: static std::unique_ptr<Singleton>& instance(); }; 
unique_ptr<Singleton>& Singleton::instance() { static unique_ptr<Singleton> instance; return instance; } Singleton& Singleton::get() { auto& instance = instance(); if (!instance) { // We cannot use make_unique<T>() as constructor is private instance = unique_ptr<Singleton>(new Singleton()); } return *instance; } void Singleton::reset() { instance().reset(); } // Private constructor Singleton::Singleton() {} 

No thread safety is required here.
Is there any advantages of using a static unique_ptr ?
What are the consequences of creating the Singleton with unique_ptr<T>(new T()) ?

Since our Singletons can carry (some) global state, a public reset() was implemented for testing purposes, is it the only way and can this be improved ?

I have found some examples of C++ singleton design patterns here. But never implemented with unique_ptr like mine.

8
  • 7
    What is gain of having std::unique_ptr<Singleton>& instance(); instead: Singleton& instance();? Are you planing to allow external code to destroy instance of Singelton? Commented Jan 26, 2023 at 16:56
  • If you are going to use unique_ptr, why not declare and initialize it in get() and get rid of instance()? Singleton& Singleton::get() { static unique_ptr<Singleton> instance(new Singleton()); return *instance; } For that matter, why use a unique_ptr at all? Do you really need to reset() a singleton? The typical (and thread-safe) implementation is to just use a static object, eg: Singleton& Singleton::get() { static Singleton instance; return instance; } Commented Jan 26, 2023 at 17:09
  • I can't think of any benefit of unique_ptr here. All this implementation has done is reduce the thread safety. Singleton& Singleton::get() { static Singleton instance; return instance; } is more thread safe and has the same result. Thread safety may not be important now, but it doesn't hurt either. Commented Jan 26, 2023 at 17:12
  • Thank you for your answers, when a create() and get() is needed (e.g creation with parameters) instance() is just a shortcut. I apologize, it's not very useful in my example. Commented Jan 26, 2023 at 17:29
  • 2
    There is no need to use a unique_ptr for a singleton. Use a Meyers' Singleton instead Commented Jan 26, 2023 at 17:37

4 Answers 4

1

There are exists two ways to reset Meyer's singleton:

#include <new> class Singleton { public: static Singleton& instance() { static Singleton instance; return instance; } virtual ~Singleton() = default; // Option 1 - easy and convinient if Singleton is copyable or movable void reset1() { *this = {}; } // Option 2 - works always void reset2() { this->~Singleton(); new (this) Singleton; } private: Singleton() {} }; 

2nd option is basically doing exactly what you are doing with releasing/creating std::unique_ptr, except without deallocation/allocation of storage.

Sign up to request clarification or add additional context in comments.

3 Comments

I have a this is unavailable for static member functions error
This has another advantage over the unique_ptr method: If somebody holds a reference to the singleton (which seems a sufficiently sensible thing to do), their reference won't be invalidated by the reset().
@Moulagaufres If you want reset() to be static then use &instance() instead of this.
0
  1. You'd get lazy instance creation if you use a pointer as opposed to a reference.
  2. If the reset() is a logical reset, you won't need a pointer, a reference would do but, if the requirement is that of a memory reset, you'll need it.
  3. Since the lifetime of the static singleton instance is the whole application lifetime, you don't need to care about the RAII benefit that you get with unique ptr.
  4. But, you'd use unique_ptr to indicate exclusive ownership over the resource and some guidelines forbid using raw pointers for non-owning
  5. The current code allows copying and moving of your instance, breaking the Singleton invariances.

Comments

-1

There is no need to use std::unique_ptr. Use references

class Singleton { public: static Singleton& instance(); virtual ~Singleton() = default; // Used for unit tests void reset(); private: Singleton(); int stuff; }; Singleton& Singleton::instance() { static Singleton instance; return instance; } void Singleton::reset() { stuff = 0; } // Private constructor Singleton::Singleton() {} 

2 Comments

TY but this does not makes sense for me: void Singleton::reset() { instance().reset(); } as we are not resetting the unique_ptr
True. I have changed the answer.
-1

Note that this design is dominated by your requirement for a reset function. This prevents you from using certain Singleton implementations, like e.g. Meyer's Singleton.

In general you would want a singleton implementation to not allow the implementation of a reset method, because now your singleton is not really a singleton anymore. But it might of course make sense to "water down" the singleton for testing purposes.

If multithreading-safety is not a concern, your singleton implementation is overly complicated and could be reduced to:

class Singleton { public: static Singleton& get() { if (!mInstance) { mInstance = std::unique_ptr<Singleton>(new Singleton()); } return *mInstance; } static void reset() { mInstance.reset(); } private: static inline std::unique_ptr<Singleton> mInstance{}; }; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.