No no no no no. This approach still needs heap allocation, and you still need to chase a pointer for every access to your singleton. That's silly. There's a much better way. Here it is, roughly speaking.
template<typename T>
struct singleton_bss {
T& get() {
return * ((T*) &this->buffer[0]);
}
void init(T&& value) {
new ( (T*) &this->buffer[0] ) T(std::forward<T> (value));
}
union {
char buffer[sizeof(T)];
long align; // adjust to taste
};
};
singleton_bss<mything> g_thing;
This approach has the huge advantage of not doing any heap allocation. The storage for g_thing lives directly in bss, the portion of your processes' address space initialized by the operating system. g_thing.init() cannot fail if T's constructor is non-throwing --- singleton_bss allocates no memory!
Access to g_thing is much more efficient than access to a typical singleton. There's no pointer-to-the-instance stored in the singleton, so there's no pointer chasing. Access to g_thing is exactly as efficient as access to a plain global variable, which is as efficient as variable access can be.
You can trivially construct a version of singleton_bss that does lazy initialization, takes multiple parameters, destroys the object on module unload, and so on.
Thanks for the tip --- alignas slipped my mind. The compiler I use for most of my work doesn't yet support alignas (or unrestricted unions). I believe a VC++-specific equivalent would for the former trick would be __declspec(align(__alignof(T))).
Yeah, you are right, alignas is still unsupported in many compilers. clang 3.2 supports it. However, unrestricted unions has been supported in many compilers for a long time now. I would use that in this case, since you already know the type 'T'.
Access to g_thing is much more efficient than access to a typical singleton. There's no pointer-to-the-instance stored in the singleton, so there's no pointer chasing. Access to g_thing is exactly as efficient as access to a plain global variable, which is as efficient as variable access can be.
You can trivially construct a version of singleton_bss that does lazy initialization, takes multiple parameters, destroys the object on module unload, and so on.