Slightly easier way of creating singletons


#1

This is pretty much the same as juce_DeclareSingleton, except it uses template classes instead of macros. So instead of writing

[code]class Foo {
juce_DeclareSingleton(Foo,true)
};

juce_ImplementSingleton(Foo)[/code]

you can write

class Foo : public Singleton<Foo> { };

Here’s the Singleton class:

[code]template
class Singleton {
private:
static ClassName* singletonInstance;
static CriticalSection singletonLock;

public:
static ClassName* getInstance()
{
if (singletonInstance == 0)
{
const ScopedLock sl (singletonLock);
if (singletonInstance == 0)
{
static bool alreadyInside = false;
static bool createdOnceAlready = false;
const bool problem = alreadyInside || createdOnceAlready;
jassert (!problem);
if (! problem)
{
createdOnceAlready = true;
alreadyInside = true;
ClassName* newObject = new ClassName(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */
alreadyInside = false;
singletonInstance = newObject;
}
}
}

    return singletonInstance;
}

static inline ClassName* getInstanceWithoutCreating() throw()
{
    return singletonInstance;
}

static void deleteInstance()
{
    const ScopedLock sl (singletonLock);
    if (singletonInstance != 0)
    {
        ClassName* const old = singletonInstance;
        singletonInstance = 0;
        delete old;
    }
}

void clearSingletonInstance() throw()
{
    if (singletonInstance == this)
        singletonInstance = 0;
}

};

template ClassName* Singleton::singletonInstance = 0;
template CriticalSection Singleton::singletonLock;
[/code]


#2

That works perfect in non-DLL’s. If you are exporting a class outside of a dll that uses that, then you also need to define the vars in the implementation file and override the template/virtual methods as well.

[code]
// header
class Foo : public Singleton
{
};

// implementation
template<> Foo* Singleton::singletonInstance = 0;
Foo* Foo::getInstance(void)
{
// etc…
}
Foo* Foo::getInstanceWithoutCreating(void)
{
return singletonInstance;
}[/code]

Possibly the other two as well. If you don’t, things begin to act very weird across dll boundaries.

Personally I prefer to have this style:

class myFoo
{
private:
    myFoo(void) { /* Program startup... */ }
    ~myFoo(void) { /* Usual shutdown stuff, called upon program exit if getInstance was ever called */ }

public:
    static myFoo& getInstance(void)
    {
        static myFoo myInstance;
        return myInstance;
    }

    // etc...
}

I treat singleton’s as program instances, not things that can be created/destroyed on a whim, and this enforces that, as well as always working across bounds. If you ever can create/destroy a singleton, then you are not using the singleton pattern and should probably be better off as another style.


#3

That makes sense (except for the dll oddities); I wonder why it’s not implemented like that in juce.


#4

Originally I did write a template-based singleton very similar to this, but had so many linking problems, compiler incompatibilities, etc, that I gave up and used macros instead.


#5

Hi,

About the singleton implemented in Juce, I see you use the Double-Checked Locking Pattern. While looking for information about what Boost libraries propose, I found a discussion about Singleton pattern in multi-threaded environment: http://lists.boost.org/boost-users/2010/01/55601.php

I’m not a multi-threading expert, but looking at the pdf document by Alexandrescu in this link, it seems like Double-Checked locking is not enough with some compilers that do more optimizations than the average. It also talks about the usage of the “volatile” keyword in such purpose.

Have you ever encountered any problems with the current singleton macro in Juce? Is it worth trying to enhance it?


#6

I’ve also read that article, but it seems a little over-paranoid to me - it seems that in all but the most bizarre cases, the chances of a thread-collision when creating a singleton are incredibly small, as it’ll only happen once in your program’s run.

In practice I find that very few singletons actually need to be robust for multi-threaded access anyway. And even when they are, I often just use a non-locked singleton, which I instantiate safely before the threading begins, because that’ll actually perform a lot faster.


#7

Thanks for the answer, that’s exactly what I wanted to hear :wink:


#8