I've implemented the phoenix-singleton as a class template with boost inspired by Modern C++ Design. The code compiles fine with MSVC 2013 - and it seems to work, but I'm new to multi-threaded programming and Boost. Are there any pitfalls in the code? Improvements?
TSingleton.h
#ifndef TSINGLETON_H
#define TSINGLETON_H
#include <cstdlib>
#include <boost/atomic.hpp>
#include <boost/thread/mutex.hpp>
template<typename T>
class TSingleton{
public:
static T& getInstance();
protected:
inline explicit TSingleton();
TSingleton(const TSingleton&);
TSingleton& operator=(const TSingleton&);
virtual ~TSingleton();
static void _CreateInstance();
static void _Phoenix();
static void _KillPhoenix();
static boost::atomic<T*> _instance;
static boost::atomic<bool> _destroyed;
static boost::mutex _instantiation_mutex;
};
template<typename T>
boost::atomic<bool> TSingleton<T>::_destroyed = (boost::atomic<bool>) false;
template<typename T>
boost::atomic<T*> TSingleton<T>::_instance = (boost::atomic<T*>) nullptr;
template<typename T>
boost::mutex TSingleton<T>::_instantiation_mutex;
template<typename T>
TSingleton<T>::~TSingleton(){
TSingleton::_destroyed = true;
TSingleton::_instance = nullptr;
}
template<typename T>
T& TSingleton<T>::getInstance(){
T* tmp = TSingleton::_instance.load(boost::memory_order_consume);
if (!tmp){
boost::mutex::scoped_lock guard(TSingleton::_instantiation_mutex);
tmp = TSingleton::_instance.load(boost::memory_order_consume);
if (!tmp){
if (TSingleton::_destroyed){
TSingleton::_Phoenix();
}else{
TSingleton::_CreateInstance();
}
tmp = TSingleton::_instance.load(boost::memory_order_consume);
}
}
return *tmp;
}
template<typename T>
void TSingleton<T>::_CreateInstance(){
static T instance;
TSingleton::_instance.store(&instance, boost::memory_order_release);
}
template<typename T>
void TSingleton<T>::_Phoenix(){
TSingleton::_CreateInstance();
new(TSingleton::_instance) T;
std::atexit(TSingleton::_KillPhoenix);
TSingleton::_destroyed = false;
}
template<typename T>
void TSingleton<T>::_KillPhoenix(){
T* tmp = TSingleton::_instance.load(boost::memory_order_consume);
tmp->~T();
TSingleton::_destroyed = true;
TSingleton::_instance = nullptr;
}
#endif // TSINGLETON_H
Simple usage example:
#include <iostream>
#include "TSingleton.h"
class Foo{
public:
void bar(){ std::cout << "bar" << std::endl; }
};
int main(int argc, char **argv){
Foo& myfoo = TSingleton<Foo>::getInstance();
myfoo.bar();
return 0;
}