CARMA C++
Singleton.h
Go to the documentation of this file.
1 
25 #ifndef CARMA_UTIL_SINGLETON_H
26 #define CARMA_UTIL_SINGLETON_H
27 
28 #include <stdexcept>
29 #include <typeinfo>
30 
31 #include "carma/util/demangle.h"
32 #include "carma/util/PthreadMutex.h"
33 #include "carma/util/ScopedPthreadMutexLock.h"
34 
35 
36 namespace carma {
37 namespace util {
38 
125  template <class TYPE, template <class> class InstantiationPolicy>
126  class Singleton;
127 
135  template <class TYPE>
137 
145  template <class TYPE>
147 
191  template <class TYPE>
193 
194 // -----------------------------------------------------------------------------
195  template <class TYPE, template<class> class InstantiationPolicy>
196  class Singleton {
197  public:
198 
204  static TYPE& instance();
205 
206  protected:
207 
208  typedef enum INSTANCE_STATE {
209  NO_INSTANCE, // Make sure this stays first...
210  INSTANCE_CREATED,
211  INSTANCE_DESTROYED,
212  NUM_INSTANCE_STATES
213  } InstanceStateType;
214 
215  explicit Singleton(); // Allow subclassing...
216  virtual ~Singleton();
217 
218  // Let instantiation policies have access to destroyInstance().
219  // This allows the policies to have finer grained control over their
220  // lifetime and destruction. Prior solution used a single lifetime.
221  friend class InstantiationPolicy<TYPE>;
222 
228  static void destroyInstance();
229 
230  static TYPE* instancePtr_; // Guaranteed init to 0 (thanks Tom).
231  static InstanceStateType state_; // Initializes to NO_INSTANCE
232 
233  private:
234 
235  };
236 
237  template <class TYPE, template<class> class InstantiationPolicy>
239  {
240  static carma::util::PthreadMutex lock;
241 
242  // Use Double-Checked Locking - See 'Double-Checked Locking - An
243  // Optimization Pattern for Efficiently Initializing and Accessing
244  // Thread-safe Objects'
245  // http://www.cs.wustl.edu/~schmidt/PDF/DC-Locking.pdf
246  if (!instancePtr_) {
247  ScopedPthreadMutexLock guard(lock);
248  if (!instancePtr_) {
249 
250  if (state_ != NO_INSTANCE)
251  throw std::logic_error(carma::util::demangleTypeName(
253  + "::instance() - Invalid Singleton state.");
254 
255  instancePtr_ = InstantiationPolicy<TYPE>::createInstance();
256  state_ = INSTANCE_CREATED;
257  }
258  }
259 
260  if (state_ != INSTANCE_CREATED)
261  throw std::logic_error(carma::util::demangleTypeName(
263  + "::instance() - Invalid Singleton state.");
264 
265  return *instancePtr_;
266  }
267 
268  template <class TYPE, template<class> class InstantiationPolicy>
270  {
271  if (state_ != INSTANCE_CREATED)
272  throw std::logic_error(carma::util::demangleTypeName(
274  + "::instance() - Invalid Singleton state.");
275  InstantiationPolicy<TYPE>::deleteInstance(instancePtr_);
276  instancePtr_ = 0;
277  state_ = INSTANCE_DESTROYED;
278  }
279 
280  template <class TYPE, template<class> class InstantiationPolicy>
282 
283  template <class TYPE, template<class> class InstantiationPolicy>
284  Singleton<TYPE, InstantiationPolicy>::~Singleton() {};
285 
286  template <class TYPE, template<class> class InstantiationPolicy>
287  TYPE* Singleton<TYPE, InstantiationPolicy>::instancePtr_;
288 
289  template <class TYPE, template<class> class InstantiationPolicy>
290  typename Singleton<TYPE, InstantiationPolicy>::InstanceStateType
291  Singleton<TYPE, InstantiationPolicy>::state_;
292 
293 // -----------------------------------------------------------------------------
294 // Create With New Instantiation Policy.
295 // -----------------------------------------------------------------------------
296  template <class TYPE>
297  class CreateWithNewPolicy {
298  public:
299  static TYPE* createInstance();
300  static void deleteInstance(TYPE * ptr);
301  private:
302 
303  CreateWithNewPolicy();
304  ~CreateWithNewPolicy();
305  };
306 
307  template <class TYPE>
308  CreateWithNewPolicy<TYPE>::CreateWithNewPolicy() {}
309 
310  template <class TYPE>
311  CreateWithNewPolicy<TYPE>::~CreateWithNewPolicy() {
313  }
314 
315  template <class TYPE>
316  TYPE* CreateWithNewPolicy<TYPE>::createInstance()
317  {
318  static CreateWithNewPolicy doomed; // Use self instance to bound life.
319  return new TYPE; // Create instance
320  }
321 
322  template <class TYPE>
323  void CreateWithNewPolicy<TYPE>::deleteInstance(TYPE * ptr)
324  {
325  delete ptr; // Delete instance
326  }
327 
328 // -----------------------------------------------------------------------------
329 // Create Static Instantiation Policy.
330 // -----------------------------------------------------------------------------
331  template <class TYPE>
332  class CreateStaticPolicy {
333  public:
334  static TYPE* createInstance();
335  static void deleteInstance(TYPE * ptr);
336  private:
337 
338  CreateStaticPolicy();
339  ~CreateStaticPolicy();
340 
341  };
342 
343  template <class TYPE>
344  CreateStaticPolicy<TYPE>::CreateStaticPolicy() {}
345 
346  template <class TYPE>
347  CreateStaticPolicy<TYPE>::~CreateStaticPolicy() {
349  }
350 
351  template <class TYPE>
352  TYPE* CreateStaticPolicy<TYPE>::createInstance()
353  {
354  static CreateStaticPolicy doomed; // Use self instance to bound life.
355  static TYPE instance; // Create instance as a static variable
356  return &instance;
357  }
358 
359  template <class TYPE>
360  void CreateStaticPolicy<TYPE>::deleteInstance(TYPE * ptr)
361  {
362  // Nothing - let the system cleanup.
363  }
364 
365 // -----------------------------------------------------------------------------
366 // Create With New Unmanaged Instantiation Policy.
367 // -----------------------------------------------------------------------------
368  template <class TYPE>
369  class CreateWithNewUnmanagedPolicy {
370  public:
371  static TYPE* createInstance();
372  static void deleteInstance(TYPE * ptr);
373  };
374 
375  template <class TYPE>
376  TYPE* CreateWithNewUnmanagedPolicy<TYPE>::createInstance()
377  {
378  return new TYPE;
379  }
380 
381  template <class TYPE>
382  void CreateWithNewUnmanagedPolicy<TYPE>::deleteInstance(TYPE * ptr)
383  {
384  // Nothing - User is responsible for their own deletion scheme.
385  }
386 
387 }} // End namespace carma::util
388 #endif
::std::string demangleTypeName(const char *mangledName)
Returns a human readable name for the type whose compiler mangled name is passed in.
Singleton creation policy which causes instances to be allocated with new (on the heap)...
Definition: Singleton.h:136
static TYPE & instance()
Retrieve a reference to underlying instance.
Definition: Singleton.h:238
Thread-safe, templatized Singleton class with policy based creation.
Definition: Singleton.h:126
Singleton creation policy which causes instances to be created in function local static memory...
Definition: Singleton.h:146
Interface file for the demangling routines.
static void destroyInstance()
Should be called when instance is destroyed.
Definition: Singleton.h:269
Singleton creation policy which causes instances to be allocated with new (on the heap) but which pro...
Definition: Singleton.h:192
A simple wrapper class that makes use of ::pthread_mutex_t easier in a C++ world. ...
Definition: PthreadMutex.h:41