Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    195
  • comments
    198
  • views
    104193

Half a singleton

Sign in to follow this  
SiCrane

87 views

One thing I've noticed about singletons in C++ is that they're usually used to solve two related problems: the one only one object of a class problem and the order of initialization problem. Of the two, the order of initialization problem is probably more significant, but rarely gets any fanfare. This usually comes up in static member variables of classes, which are essentially glorified global variables living in a class's scope.

For example, the master lock I described a couple of entries ago is an example of such a pseudo-singleton. It has all the scaffolding associated with a singleton, except for the one object per class part. There is only one master lock object, but it other mutexes may be spawned in the program freely. One approach to this is a generalization of the Singleton scheme.

Prepackaged C++ Singleton implementations are currently usually done as template classes parameterized on the singleton's class type. Such classes have declarations that often look like: template class Singleton. If you generalize this to template class Singleton then with some types T, you can use this kind of template to address the initialization order of "static" class variables.

This can be extended to different components used by singleton templates. For example, I now use this guy in my code library:

template <typename T, typename Key = T>
class CreateStatic {
public:
static T * Create(void) {
const int function_priority = 2;
assert_cpre(!checker);
#ifdef _DEBUG
checker =
#endif
new (&buffer) T;
assert_cpost(checker);
assert_cpost(checker == reinterpret_cast(&buffer));
return reinterpret_cast(&buffer);
}
static void Destroy(T * ptr) {
const int function_priority = 2;
assert_cpre(checker == ptr);
assert_cpre(checker == reinterpret_cast(&buffer));
get()->~T();
#ifdef _DEBUG
checker = 0;
#endif
assert_cpost(!checker);
}
static T * get(void) {
const int function_priority = 3;
assert_cpre(checker);
assert_cpre(checker == reinterpret_cast(&buffer));
return reinterpret_cast(&buffer);
}
private:
static const int class_priority = 2;
#ifdef _DEBUG
static T * checker;
#endif
static union BufferType {
char data_[sizeof(T)];
AlignType dummy_;
} buffer;
};
#ifdef _DEBUG
template <typename T, typename Key> T * CreateStatic::checker = 0;
#endif
template <typename T, typename Key> typename CreateStatic::BufferType CreateStatic::buffer;

It's as ugly as sin, but can be used as a backend for more full blown singleton solutions, to wrap the creation/destruction and access to the data. For example, this class backs the master lock I described earlier, as well as my ClassLevelLockable<> class, all of which use CreateStatic<> with T = Mutex, but different Key types.
Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!