Skip to main content

[C++] Automatic singleton template

Forum

Being way less than gifted with artistic skills, I won't torture
people with any sketches I've done (no, I'm not being modest,
I really _do_ suck at art [;)])

Instead, here's some code I wrote that implements a reasonably
easy-to-use (and IMHO rather nifty) singleton template class...

Stuff to go in the header file "autosing.hxx":

[code]#ifndef AUTOSING_H
#define AUTOSING_H

template
class AutoSingleton
{
public:
AutoSingleton() {}

~AutoSingleton()
{
delete mptSingleton;
}

static Tx * instance()
{
if (mptSingleton == NULL)
mptSingleton = new Tx();

return mptSingleton;
}

private:
static Tx * mptSingleton;
};

#define SingletonInstance(Type) AutoSingleton::instance()

#define DefineSingleton(Type) AutoSingleton AS_ ## Type; Type * AutoSingleton::mptSingleton = NULL

#define DeclareSingleton(Type) extern AutoSingleton AS_ ## Type

#endif /* AUTOSING_H */[/code]To use it, add this to your class's header:

[code]class MonsterGenerator
{
public:
// ...
};

DeclareSingleton(MonsterGenerator);[/code]Then to your class's implementation, add:

[code]MonsterGenerator::MonsterGenerator()
{
// ...
}

DefineSingleton(MonsterGenerator);[/code]Then finally to use it in your code, include the header and do the following:
[code]int main()
{
Monster * ptMonster = SingletonInstance(MonsterGenerator)->generateMonster();
return 0;
}
[/code]Got some other geeky code samples? Post 'em ;)

Cheers,

CombatWombat the exhibitionist (umm, that didn't quite come out right, did it [;)])

Submitted by Daemin on Sun, 01/06/03 - 11:45 PM Permalink

Yeah, that's alright, but there are a few problems with it, as in the constructor's still public, which could lead to some trouble, and you can also call the constructor of the object that you're wrapping too, so it wouldn't really be a singleton.

But I've also noticed that in your case you delete the pointer object upon destruction of an element, hence it isn't really a singleton, because the first time an object of that type gets deleted then all of them get deleted, and you end up with some bad runtime errors. I think you also need to implement some sort of reference counting into that code to make it work properly.

Instead of going that way, I made my singleton class be instanciated on first call to Get()... and all it is:

quote:template class TSingleton
{
public:

inline static T & Get( void );
};

template inline T & TSingleton::Get( void )
{
static T singleton;
return singleton;
}

with the application being something like:

quote:
class SingleFoo : public TSingleton
{
private:
friend class TSingleton;
SingleFoo();
public:
// blah
};

This allows you then to create a nice singleton class that cannot have multiple instantiations of it in the program, although you do have to make the parent singleton class a friend, so that it can access the private / protected constructors.

Then all you need to do to call functions is SimpleFoo::Get().whatever() etc.

(P.S. Shouldn't this be moved to the programming forum?)

Submitted by redwyre on Mon, 02/06/03 - 12:31 AM Permalink

Here is my singleton class, you inherit from it, and the instance of the object is created on the first call of GetInstance(), and is automatically deleted when the program closes (if it hasn't been already)

They way I use it either as-is, or by #define g_pType Type::GetInstance() (which seems so evil :( )

[code]
#ifndef SINGLETON_HPP_INCLUDED
#define SINGLETON_HPP_INCLUDED
#include "Core.hpp"
namespace thang
{
template< typename Type >
class Singleton
{
protected:
Singleton( Type* pInstance ) { ms_pGlobalInstance = pInstance; }
Singleton() { }
Singleton( const Singleton& ) { }
~Singleton() { }

private:
static Type* ms_pGlobalInstance;

public:
static Type* GetInstance()
{
if( !ms_pGlobalInstance )
{
ms_pGlobalInstance = new Type();
atexit( Delete );
}
return ms_pGlobalInstance;
}

static void T_CDECL Delete()
{
delete ms_pGlobalInstance;
ms_pGlobalInstance = 0;
}

protected:
void SetThisInstance( Type* pInstance )
{
ms_pGlobalInstance = pInstance;
}
};

template
Type* Singleton::ms_pGlobalInstance = 0;

} // namespace thang

#endif // SINGLETON_HPP_INCLUDED
[/code]

Singleton::Singleton( Type* pInstance ); is there as a kind of hack, it allows things to use GetInstance() while it is in the Type's ctor

Submitted by CombatWombat on Mon, 02/06/03 - 2:47 AM Permalink

quote:Originally posted by Daemin

Yeah, that's alright, but there are a few problems with it, as in the constructor's still public, which could lead to some trouble, and you can also call the constructor of the object that you're wrapping too, so it wouldn't really be a singleton.

But I've also noticed that in your case you delete the pointer object upon destruction of an element, hence it isn't really a singleton, because the first time an object of that type gets deleted then all of them get deleted, and you end up with some bad runtime errors. I think you also need to implement some sort of reference counting into that code to make it work properly.

Sure, I appreciate the issues that you mention. Given appropriate
use, it works nicely for me.

quote:Instead of going that way, I made my singleton class be instanciated on first call to Get()... and all it is:

But how can you get by without using a funky ## operator? [8D]

Yeah, I think your solution is a safer one (esp where inexperienced
developers are involved in a project).

quote:(P.S. Shouldn't this be moved to the programming forum?)

Yeah probably since we're now discussing it :) My bad...

Submitted by lava monkey on Mon, 02/06/03 - 5:05 AM Permalink

I've never really bothered making a singleton class cause I?ve never needed to make anything a singleton b4, but if the whole idea of it is just stop people from accessing the constructors and making instances of it.
Why don?t you just avoid making instances of it instead?
Also what type of things are you making a singleton too ?

Submitted by Daemin on Mon, 02/06/03 - 7:37 AM Permalink

lava_monkey: The way you talk about using singletons is the way I was doing it, keeping a single static pointer and only instantiate the object once. While it works, there are certain evil things that can happen. I've found that if you actually have a singleton class it makes it a whole lot simpler and easier to use. Plus then it's automatically destroyed.

CombatWombat: I use the ## operator only when I need to, in the debug macros for instance. And another thing is that you're not setting the pointer to NULL after you've deleted it, therefore you could be using invalid memory occcasionally.

Submitted by lava monkey on Mon, 02/06/03 - 8:39 AM Permalink

haha, no i think posting code is a good idea, also asking questions about different ways to code something or asking 4 help. I usualy use experts-exchange, but i'll try to post things here 1st.

Submitted by souri on Mon, 02/06/03 - 1:31 PM Permalink

I've moved this to the programmers section, I hope you don't mind!

Submitted by CombatWombat on Mon, 02/06/03 - 8:33 PM Permalink

quote:Originally posted by Daemin

Instead of going that way, I made my singleton class be instanciated on first call to Get()... and all it is:

The more I think about your solution the more it grows on me :)

I'd gone the way I had because I was trying to be quite deliberate
about avoiding problems with initialisation order of globals but
still wanted to clean the singleton up properly. (ie if you have
your instances as statics of a class then you have no control over
the order they get initialised).

But statics within a function is a much more elegant solution. You
still have your control over order of intialisation.

Thanks for the info on your template idea [:)]

Cheers,

CW

Submitted by Daemin on Mon, 02/06/03 - 9:32 PM Permalink

CombatWombat: I kind of discovered it within the pages of Game Architecture and Design, that's still a damn good book.

Forum

Being way less than gifted with artistic skills, I won't torture
people with any sketches I've done (no, I'm not being modest,
I really _do_ suck at art [;)])

Instead, here's some code I wrote that implements a reasonably
easy-to-use (and IMHO rather nifty) singleton template class...

Stuff to go in the header file "autosing.hxx":

[code]#ifndef AUTOSING_H
#define AUTOSING_H

template
class AutoSingleton
{
public:
AutoSingleton() {}

~AutoSingleton()
{
delete mptSingleton;
}

static Tx * instance()
{
if (mptSingleton == NULL)
mptSingleton = new Tx();

return mptSingleton;
}

private:
static Tx * mptSingleton;
};

#define SingletonInstance(Type) AutoSingleton::instance()

#define DefineSingleton(Type) AutoSingleton AS_ ## Type; Type * AutoSingleton::mptSingleton = NULL

#define DeclareSingleton(Type) extern AutoSingleton AS_ ## Type

#endif /* AUTOSING_H */[/code]To use it, add this to your class's header:

[code]class MonsterGenerator
{
public:
// ...
};

DeclareSingleton(MonsterGenerator);[/code]Then to your class's implementation, add:

[code]MonsterGenerator::MonsterGenerator()
{
// ...
}

DefineSingleton(MonsterGenerator);[/code]Then finally to use it in your code, include the header and do the following:
[code]int main()
{
Monster * ptMonster = SingletonInstance(MonsterGenerator)->generateMonster();
return 0;
}
[/code]Got some other geeky code samples? Post 'em ;)

Cheers,

CombatWombat the exhibitionist (umm, that didn't quite come out right, did it [;)])


Submitted by Daemin on Sun, 01/06/03 - 11:45 PM Permalink

Yeah, that's alright, but there are a few problems with it, as in the constructor's still public, which could lead to some trouble, and you can also call the constructor of the object that you're wrapping too, so it wouldn't really be a singleton.

But I've also noticed that in your case you delete the pointer object upon destruction of an element, hence it isn't really a singleton, because the first time an object of that type gets deleted then all of them get deleted, and you end up with some bad runtime errors. I think you also need to implement some sort of reference counting into that code to make it work properly.

Instead of going that way, I made my singleton class be instanciated on first call to Get()... and all it is:

quote:template class TSingleton
{
public:

inline static T & Get( void );
};

template inline T & TSingleton::Get( void )
{
static T singleton;
return singleton;
}

with the application being something like:

quote:
class SingleFoo : public TSingleton
{
private:
friend class TSingleton;
SingleFoo();
public:
// blah
};

This allows you then to create a nice singleton class that cannot have multiple instantiations of it in the program, although you do have to make the parent singleton class a friend, so that it can access the private / protected constructors.

Then all you need to do to call functions is SimpleFoo::Get().whatever() etc.

(P.S. Shouldn't this be moved to the programming forum?)

Submitted by redwyre on Mon, 02/06/03 - 12:31 AM Permalink

Here is my singleton class, you inherit from it, and the instance of the object is created on the first call of GetInstance(), and is automatically deleted when the program closes (if it hasn't been already)

They way I use it either as-is, or by #define g_pType Type::GetInstance() (which seems so evil :( )

[code]
#ifndef SINGLETON_HPP_INCLUDED
#define SINGLETON_HPP_INCLUDED
#include "Core.hpp"
namespace thang
{
template< typename Type >
class Singleton
{
protected:
Singleton( Type* pInstance ) { ms_pGlobalInstance = pInstance; }
Singleton() { }
Singleton( const Singleton& ) { }
~Singleton() { }

private:
static Type* ms_pGlobalInstance;

public:
static Type* GetInstance()
{
if( !ms_pGlobalInstance )
{
ms_pGlobalInstance = new Type();
atexit( Delete );
}
return ms_pGlobalInstance;
}

static void T_CDECL Delete()
{
delete ms_pGlobalInstance;
ms_pGlobalInstance = 0;
}

protected:
void SetThisInstance( Type* pInstance )
{
ms_pGlobalInstance = pInstance;
}
};

template
Type* Singleton::ms_pGlobalInstance = 0;

} // namespace thang

#endif // SINGLETON_HPP_INCLUDED
[/code]

Singleton::Singleton( Type* pInstance ); is there as a kind of hack, it allows things to use GetInstance() while it is in the Type's ctor

Submitted by CombatWombat on Mon, 02/06/03 - 2:47 AM Permalink

quote:Originally posted by Daemin

Yeah, that's alright, but there are a few problems with it, as in the constructor's still public, which could lead to some trouble, and you can also call the constructor of the object that you're wrapping too, so it wouldn't really be a singleton.

But I've also noticed that in your case you delete the pointer object upon destruction of an element, hence it isn't really a singleton, because the first time an object of that type gets deleted then all of them get deleted, and you end up with some bad runtime errors. I think you also need to implement some sort of reference counting into that code to make it work properly.

Sure, I appreciate the issues that you mention. Given appropriate
use, it works nicely for me.

quote:Instead of going that way, I made my singleton class be instanciated on first call to Get()... and all it is:

But how can you get by without using a funky ## operator? [8D]

Yeah, I think your solution is a safer one (esp where inexperienced
developers are involved in a project).

quote:(P.S. Shouldn't this be moved to the programming forum?)

Yeah probably since we're now discussing it :) My bad...

Submitted by lava monkey on Mon, 02/06/03 - 5:05 AM Permalink

I've never really bothered making a singleton class cause I?ve never needed to make anything a singleton b4, but if the whole idea of it is just stop people from accessing the constructors and making instances of it.
Why don?t you just avoid making instances of it instead?
Also what type of things are you making a singleton too ?

Submitted by Daemin on Mon, 02/06/03 - 7:37 AM Permalink

lava_monkey: The way you talk about using singletons is the way I was doing it, keeping a single static pointer and only instantiate the object once. While it works, there are certain evil things that can happen. I've found that if you actually have a singleton class it makes it a whole lot simpler and easier to use. Plus then it's automatically destroyed.

CombatWombat: I use the ## operator only when I need to, in the debug macros for instance. And another thing is that you're not setting the pointer to NULL after you've deleted it, therefore you could be using invalid memory occcasionally.

Submitted by lava monkey on Mon, 02/06/03 - 8:39 AM Permalink

haha, no i think posting code is a good idea, also asking questions about different ways to code something or asking 4 help. I usualy use experts-exchange, but i'll try to post things here 1st.

Submitted by souri on Mon, 02/06/03 - 1:31 PM Permalink

I've moved this to the programmers section, I hope you don't mind!

Submitted by CombatWombat on Mon, 02/06/03 - 8:33 PM Permalink

quote:Originally posted by Daemin

Instead of going that way, I made my singleton class be instanciated on first call to Get()... and all it is:

The more I think about your solution the more it grows on me :)

I'd gone the way I had because I was trying to be quite deliberate
about avoiding problems with initialisation order of globals but
still wanted to clean the singleton up properly. (ie if you have
your instances as statics of a class then you have no control over
the order they get initialised).

But statics within a function is a much more elegant solution. You
still have your control over order of intialisation.

Thanks for the info on your template idea [:)]

Cheers,

CW

Submitted by Daemin on Mon, 02/06/03 - 9:32 PM Permalink

CombatWombat: I kind of discovered it within the pages of Game Architecture and Design, that's still a damn good book.