“extensible singleton” using template function create instance Instance with singleton pattern in C++ ? How is it done?

I am totally stuck on how to make this work and i just want a straight explanation that i don't need to decrypt. I gotta make an abstract class following singleton pattern which then uses template function to create a single "instance" of any concrete class also can't quite get an understanding of lazy initialization. If anybody can explain this in words for real beginners or just give me code that works so i can understand at least the syntax for this would be great. The following is the criteria for my abstract class: AbstractAssetRegister template instance() — static member function to return the single instance of any of its subclasses. Use lazy initialisation to create the single instance if one does not currently exist. To support extensibility, this function will be a template function: the type parameter will specify the concrete subclass that is to be created (if the register instance does not already exist). Once an instance of a type has been created, that instance will always be returned, regardless if the function is called with a different type: i.e., there cannot be multiple register instances of different types instantiated at the same time. For example, to select the simple AssetRegister class as the singleton, the first call to this function should be: AbstractAssetRegister::instance() Note: you can create a non-template version of the function for convenience. This convenience function should log an error if it is called before an instance of any concrete register types is created.

for the conrete class all i have mentioned is : to support the extensible singleton, this class must declare AbstractAssetRegister to be a friend class . This will allow the instance() static function (which is defined in the scope of AbstractAssetRegister and not its subclasses) to access the protected constructor of AssetRegister .
Fist of all, singletons are the design errors we fight to avoid, not to embellish!

i just want a straight explanation that i don't need to decrypt

Made extra hard by swallowed angle brackets! I'm pretty sure "template instance()" in your copy-paste was meant to be "template<class T> instance()" and later on "AbstractAssetRegister::instance()" was meant to be "AbstractAssetRegister::instance<AssetRegister>()"

can't quite get an understanding of lazy initialization

with regards to singletons, this means
1) if the instance() function is never called, no object is ever created
2) on the first call to the instance() function, the object is created
3) all subsequent calls to the instance() function return the object created on that first call
in C++, this is most efficiently done with function-local statics because that's precisely what they do
1
2
3
4
Type& instance() {
    static Type obj;
    return obj;
}

although you may sometimes see Java-inspired pointer acrobatics instead, and in fact may have to use a pointer for this assignment, though it doesn't have to be complicated.

Once an instance of a type has been created, that instance will always be returned, regardless if the function is called with a different type

This is even worse than a regular singleton!

If I decypher this correctly, they want user code to be

1
2
3
AbstractAssetRegister& a1 = AbstractAssetRegister::instance<AssetRegister>(); // creates and returns an AssetRegister
AbstractAssetRegister& a2 = AbstractAssetRegister::instance<AssetRegister>(); // returns the already-created AssetRegister
AbstractAssetRegister& a3 = AbstractAssetRegister::instance<OtherRegister>(); // returns the already-created AssetRegister (!) 


since the type of the object to be created is not known until runtime, it will have to be dynamically-allocated, so..

something like this
1
2
3
4
5
6
7
8
9
10
11
12
13
struct AbstractAssetRegister {
  template<class T>
  static AbstractAssetRegister& instance() {
    if (!obj) obj = std::make_unique<T>(); // not thread-safe (unlike function-local static)
    return *obj;
  }
  // needs a virtual destructor, I'm keeping this minimal to show the singleton part
 private:
  static std::unique_ptr<AbstractAssetRegister> obj;
};
std::unique_ptr<AbstractAssetRegister> AbstractAssetRegister::obj;
struct AssetRegister : AbstractAssetRegister {};
struct OtherRegister : AbstractAssetRegister {};


live demo (with the destructor too): https://wandbox.org/permlink/2aBLUU4Kp5d6vxn7

Make some constructors private to taste (after all, singletons should offer no way to be constucted other than that "instance" thing)
Last edited on
While I agree we shouldn't strive for them, having just a few singleton's isn't too bad. There's a few in my work's codebase and I've never had trouble maintaining them (I didn't make them). They're thread safe as well. If used right, it can really cut down on the semantics to make the code more readable, especially for things that we only want one of, but the first time it initializes it, it is slow.

As far as your implementation of OP's code, yeah I would never want to see that IRL :)
(Not that you did anything bad, you're just fulfilling the OP's wishes)
Last edited on
Topic archived. No new replies allowed.