teupoui
teupoui

Reputation: 77

In C++, how to initialize static member of a private class declared inside a Singleton template?

Ok, I should simply tell that I want to make a base Singleton class that I can inherit from, and the way I want to achieve that is by a template.

In order to avoid memory leaks, I do not use directly a pointer to the instance, but a private class that will handle deleting the pointer.

Here is my actual code (not working) :

template <typename T> class Singleton
{
private:
    class PointerInstance
    {
    private:
        T* instance;
    public:
        PointerInstance() : instance(0) {}
        ~PointerInstance() { delete instance; } // no memory leak !
        T* Get()
        {
            if ( !instance ) {
                instance = new T();
            }
            return instance;
        }
    };
    static PointerInstance PInstance;
public:
    static T* pGetInstance(void)
    {
        return PInstance.pGet();
    };
protected:
    Singleton(void){};
    ~Singleton(void){};
};

And here is what a typical derived class declaration should look like :

class Child : public Singleton<Child>
{
    friend class Singleton<Child>;
    Child();
    // etc...
};

Basically what is lacking is the instance of PInstance for each T class I make as a Singleton.

My question is : is there a way to do this once and for all with a few generic lines of code in the Singleton.h containing the code above, or do I have no other choice but to add a few specific lines of code for each derived class ?

(Bonus : is there a better way to do a Singleton class in C++ ?)

Upvotes: 3

Views: 1333

Answers (4)

CashCow
CashCow

Reputation: 31455

First in general I would suggest you avoid using singletons where possible. They are horribly overused.

If you have to use them, I really do not get this new popular way (must have appeared in a journal somewhere because I see everyone using it now) of deriving from Singleton. Doing this causes as many problems as it solves.

If you have to have one though, the best way to initialise it is to use boost::once. You need to do something like this in your source where Foo is your class.

these 3 are all statically declared in Foo and private

Foo* Foo::instance = NULL;
boost::once_flag Foo::flag = BOOST_ONCE_INIT;
void Foo::init()
{
   Foo::instance = new Foo;
};

This is also static and is the public method to get the instance

Foo & Foo::getInstance()
{
   boost::call_once(init, Foo::flag);
   return *Foo::instance;
}

The constructor of Foo must not throw.

Note that this technique can be used more extensively for thread-safe once-loading lazy-evaluation situations, not just singletons. The new version of boost::once takes first the flag (which is now a struct: beware) and secondarily takes a boost::function so you can boost::bind in information for creation.

For deleting your singleton, you can create a boost::shared_ptr at compilation unit level and bind your pointer to it, and use a custom deleter that is a static member of your class so that delete can remain private. Your deleter will be able to call delete though, and your init function will have access to the deleter function (which is also private) to initialise the shared_ptr with it.

Upvotes: 0

Philipp
Philipp

Reputation: 11833

Maybe you want to take a look at Loki which already has a generic SingletonHolder<> class?

Upvotes: 0

Bart van Ingen Schenau
Bart van Ingen Schenau

Reputation: 15808

Here is a simpler way of writing a CRTP Singleton without a memory leak:

template <class T>
class Singleton
{
  friend class T;
private:
  Singleton() {};
  ~Singleton() {};
  Singleton(const Singleton&); // not implemented
  const Singleton& operator=(const Singleton&); // not implemented

public:
  static T* pGetInstance()
  {
    static T theInstance;
    return &theInstance;
  }
};

Usage is the same as in the question.

Upvotes: 2

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 507423

template <typename T> 
typename Singleton<T>::PointerInstance Singleton<T>::PInstance;

In the header outside of the classes. Note that whatever you write in PInstance's default constructor, the code will never be executed if you never call pGetInstance or never refer to PInstance in another way from non-template code. But that should be fine.

Upvotes: 5

Related Questions