В недавнем проекте мне пришлось создать класс Singleton, и после долгих поисков в Google я придумал это определение класса шаблона.Идея состоит в том, чтобы наследовать от этого шаблонного класса и сделать конструктор производного класса защищенным / закрытым.Кажется, это работает хорошо, но я использовал его только с одним классом в одном проекте, поэтому я надеялся, что некоторые из вас могут указать, если я допустил ошибки в реализации.Вот оно:
/**
* @brief
* Singleton design pattern implementation using a dynamically allocated singleton instance.
*
* The SingletonDynamic class is intended for use as a base for classes implementing the Singleton
* design pattern and require lazy initialization of the singleton object. The default
* implementation is not thread-safe, however, the derived classes can make it so by reinitializing
* the function pointers SingletonDynamic<T>::pfnLockMutex, SingletonDynamic<T>::pfnUnlockMutex
* and SingletonDynamic<T>::pfnMemoryBarrier. The member function pointers are initialized by
* default to point to placeholder functions that do not perform any function. The derived class
* must provide alternate implementations for SingletonDynamic<T>::lock_mutex(),
* SingletonDynamic<T>::unlock_mutex() and SingletonDynamic<T>::memory_barrier() respectively
* and reinitialize the respective function pointer members to these alternate implementations.
*
* @tparam T
* The type name of the derived (singleton) class
*
* @note The derived class must have a no-throw default constructor and a no-throw destructor.
* @note The derived class must list this class as a friend, since, by necessity, the derived class'
* constructors must be protected / private.
*/
template< typename T >
class SingletonDynamic
{
public:
/**
* Factory function for vending mutable references to the sole instance of the singleton object.
*
* @return A mutable reference to the one and only instance of the singleton object.
*/
static T &instance()
{
return *SingletonDynamic< T >::get_instance();
}
/**
* Factory function for vending constant references to the sole instance of the singleton object.
*
* @return A constant reference to the one and only instance of the singleton object.
*/
static const T &const_instance()
{
return *SingletonDynamic< T >::get_instance();
}
protected:
/** Default constructor */
SingletonDynamic() {}
/** Destructor */
virtual ~SingletonDynamic()
{
delete SingletonDynamic< T >::pInstance_;
}
/** Defines an alias for a function pointer type for executing functions related to thread-safety */
typedef void(*coherence_callback_type)();
/**
* Pointer to a function that will lock a mutex denying access to threads other that the current
*
* @note The function must have the signature void foo()
* @note The derived class must never set this variable to NULL, doing so will cause a crash. The
* default value must be left unchanged if this functionality is not desired.
*/
static coherence_callback_type pfnLockMutex;
/**
* Pointer to a function that will unlock a mutex allowing access to other threads
*
* @note The function must have the signature void foo()
* @note The derived class must never set this variable to NULL, doing so will cause a crash. The
* default value must be left unchanged if this functionality is not desired.
*/
static coherence_callback_type pfnUnlockMutex;
/**
* Pointer to a function that executes a memory barrier instruction that prevents the compiler
* from reordering reads and writes across this boundary.
*
* @note The function must have the signature void foo()
* @note The derived class must never set this variable to NULL, doing so will cause a crash. The
* default value must be left unchanged if this functionality is not desired.
*/
static coherence_callback_type pfnMemoryBarrier;
private:
/** The sole instance of the singleton object */
static T *pInstance_;
/** Flag indicating whether the singleton object has been created */
static volatile bool flag_;
/** Private copy constructor to prevent copy construction */
SingletonDynamic( SingletonDynamic const & );
/** Private operator to prevent assignment */
SingletonDynamic &operator=( SingletonDynamic const & );
/**
* Fetches a pointer to the singleton object, after creating it if necessary
*
* @return A pointer to the one and only instance of the singleton object.
*/
static T *get_instance()
{
if( SingletonDynamic< T >::flag_ == false ) {
/* acquire lock */
(*SingletonDynamic< T >::pfnLockMutex)();
if( SingletonDynamic< T >::pInstance_ == NULL ) {
pInstance_ = new T();
}
/* release lock */
(*SingletonDynamic< T >::pfnUnlockMutex)();
/* enforce all prior I/O to be completed */
(*SingletonDynamic< T >::pfnMemoryBarrier)();
SingletonDynamic< T >::flag_ = true;
return SingletonDynamic< T >::pInstance_;
} else {
/* enforce all prior I/O to be completed */
(*SingletonDynamic< T >::pfnMemoryBarrier)();
return SingletonDynamic< T >::pInstance_;
}
}
/**
* Placeholder function for locking a mutex, thereby preventing access to other threads. This
* default implementation does not perform any function, the derived class must provide an
* implementation if this functionality is desired.
*/
inline static void lock_mutex()
{
/* default implementation does nothing */
return;
}
/**
* Placeholder function for unlocking a mutex, thereby allowing access to other threads. This
* default implementation does not perform any function, the derived class must provide an
* implementation if this functionality is desired.
*/
inline static void unlock_mutex()
{
/* default implementation does nothing */
return;
}
/**
* Placeholder function for executing a memory barrier instruction, thereby preventing the
* compiler from reordering read and writes across this boundary. This default implementation does
* not perform any function, the derived class must provide an implementation if this
* functionality is desired.
*/
inline static void memory_barrier()
{
/* default implementation does nothing */
return;
}
};
/* Initialize the singleton instance pointer */
template< typename T >
T *SingletonDynamic<T>::pInstance_ = NULL;
/* Initialize the singleton flag */
template< typename T >
volatile bool SingletonDynamic<T>::flag_ = false;
/* Initialize the function pointer that locks the mutex */
template< typename T >
typename SingletonDynamic<T>::coherence_callback_type SingletonDynamic<T>::pfnLockMutex
= &SingletonDynamic<T>::lock_mutex;
/* Initialize the function pointer that unlocks the mutex */
template< typename T >
typename SingletonDynamic<T>::coherence_callback_type SingletonDynamic<T>::pfnUnlockMutex
= &SingletonDynamic<T>::unlock_mutex;
/* Initialize the function pointer that executes the memory barrier instruction */
template< typename T >
typename SingletonDynamic<T>::coherence_callback_type SingletonDynamic<T>::pfnMemoryBarrier
= &SingletonDynamic<T>::memory_barrier;
Меня особенно беспокоит инициализация статического члена в файле заголовка и то, не вызовет ли это множественные ошибки определения, если включен файл заголовка класса, производного от SingleDynamicв нескольких файлах.Я уже попробовал это, и это, кажется, работает, но я не могу понять, почему это работает:).
Заранее спасибо, Ашиш.
РЕДАКТИРОВАТЬ: Модифицированная реализация с использованием дизайна, основанного на политике, как предложено в принятом решении.
/**
* This is the default ConcurrencyPolicy implementation for the SingletonDynamic class. This
* implementation does not provide thread-safety and is merely a placeholder. Classes deriving from
* SingletonDynamic must provide alternate ConcurrencyPolicy implementations if thread-safety is
* desired.
*/
struct DefaultSingletonConcurrencyPolicy
{
/**
* Placeholder function for locking a mutex, thereby preventing access to other threads. This
* default implementation does not perform any function, the derived class must provide an
* alternate implementation if this functionality is desired.
*/
static void lock_mutex()
{
/* default implementation does nothing */
return;
}
/**
* Placeholder function for unlocking a mutex, thereby allowing access to other threads. This
* default implementation does not perform any function, the derived class must provide an
* alternate implementation if this functionality is desired.
*/
static void unlock_mutex()
{
/* default implementation does nothing */
return;
}
/**
* Placeholder function for executing a memory barrier instruction, thereby preventing the
* compiler from reordering read and writes across this boundary. This default implementation does
* not perform any function, the derived class must provide an alternate implementation if this
* functionality is desired.
*/
static void memory_barrier()
{
/* default implementation does nothing */
return;
}
};
/**
* @brief
* Singleton design pattern implementation using a dynamically allocated singleton instance.
*
* The SingletonDynamic class is intended for use as a base for classes implementing the Singleton
* design pattern and that dynamic allocation of the singleton object. The default implementation
* is not thread-safe; however, the class uses a policy-based design pattern that allows the derived
* classes to achieve threaad-safety by providing an alternate implementation of the
* ConcurrencyPolicy.
*
* @tparam T
* The type name of the derived (singleton) class
* @tparam ConcurrencyPolicy
* The policy implementation for providing thread-safety
*
* @note The derived class must have a no-throw default constructor and a no-throw destructor.
* @note The derived class must list this class as a friend, since, by necessity, the derived class'
* constructors must be protected / private.
*/
template< typename T, typename ConcurrencyPolicy = DefaultSingletonConcurrencyPolicy >
class SingletonDynamic : public ConcurrencyPolicy
{
public:
/**
* Factory function for vending mutable references to the sole instance of the singleton object.
*
* @return A mutable reference to the one and only instance of the singleton object.
*/
static T &instance()
{
return *SingletonDynamic< T, ConcurrencyPolicy >::get_instance();
}
/**
* Factory function for vending constant references to the sole instance of the singleton object.
*
* @return A constant reference to the one and only instance of the singleton object.
*/
static const T &const_instance()
{
return *SingletonDynamic< T, ConcurrencyPolicy >::get_instance();
}
protected:
/** Default constructor */
SingletonDynamic() {}
/** Destructor */
virtual ~SingletonDynamic()
{
delete SingletonDynamic< T, ConcurrencyPolicy >::pInstance_;
}
private:
/** The sole instance of the singleton object */
static T *pInstance_;
/** Flag indicating whether the singleton object has been created */
static volatile bool flag_;
/** Private copy constructor to prevent copy construction */
SingletonDynamic( SingletonDynamic const & );
/** Private operator to prevent assignment */
SingletonDynamic &operator=( SingletonDynamic const & );
/**
* Fetches a pointer to the singleton object, after creating it if necessary
*
* @return A pointer to the one and only instance of the singleton object.
*/
static T *get_instance()
{
if( SingletonDynamic< T, ConcurrencyPolicy >::flag_ == false ) {
/* acquire lock */
ConcurrencyPolicy::lock_mutex();
/* create the singleton object if this is the first time */
if( SingletonDynamic< T, ConcurrencyPolicy >::pInstance_ == NULL ) {
pInstance_ = new T();
}
/* release lock */
ConcurrencyPolicy::unlock_mutex();
/* enforce all prior I/O to be completed */
ConcurrencyPolicy::memory_barrier();
/* set flag to indicate singleton has been created */
SingletonDynamic< T, ConcurrencyPolicy >::flag_ = true;
return SingletonDynamic< T, ConcurrencyPolicy >::pInstance_;
} else {
/* enforce all prior I/O to be completed */
ConcurrencyPolicy::memory_barrier();
return SingletonDynamic< T, ConcurrencyPolicy >::pInstance_;
}
}
};
/* Initialize the singleton instance pointer */
template< typename T, typename ConcurrencyPolicy >
T *SingletonDynamic< T , ConcurrencyPolicy >::pInstance_ = NULL;
/* Initialize the singleton flag */
template< typename T, typename ConcurrencyPolicy >
volatile bool SingletonDynamic< T , ConcurrencyPolicy >::flag_ = false;