blocxx
BLOCXX_NAMESPACE::LazyGlobal< T, PODType, FactoryT > Class Template Reference

This class can be used to store a global variable that is lazily initialized in a thread safe manner. More...

#include <LazyGlobal.hpp>

Classes

struct  InitPtr
 

Public Member Functions

 ~LazyGlobal ()
 
T & get () const
 
 operator T& ()
 
 operator const T & () const
 
template<typename T2 >
T & operator= (const T2 &rhs)
 

Public Attributes

PODType m_pod
 
T * m_p
 
OnceFlag m_onceFlag
 

Private Member Functions

T * getPtr () const
 

Detailed Description

template<typename T, typename PODType, typename FactoryT = DefaultVariableConstructorFactory<T, PODType>>
class BLOCXX_NAMESPACE::LazyGlobal< T, PODType, FactoryT >

This class can be used to store a global variable that is lazily initialized in a thread safe manner.

It is intended as a solution to the common C++ issue with the ordering of constructor invocations during the dynamic initialization phase. See http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12 for a description and for some possible solutions. Unfortunately the soultions presented in the C++ FAQ are not thread-safe on all platforms (some versions of g++ & C standard library can initialize function-scope static variables in a thread-safe manner) and can't be used by BloCxx.

A LazyGlobal instance consists of a pointer to T that is lazily constructed and deleted when the global variable goes out of scope, an instance of PODType that is used to pass to the constructor of T when it is newed, and a ThreadOnce instance that is used to ensure the pointer is constructed in a thread safe manner.

LazyGlobal is a POD type with a destructor, and thus must be initialized using POD initialization syntax: LazyGlobal<T, PODType> myGlobalVar = BLOCXX_LAZY_GLOBAL_INIT(pod); Doing initialization in this manner happens during the static initialization phase, before any code is run, and so avoids the ordering problem. Take care that the argument is truly static data and not the result of running a function or constructor.

The pointer will be lazily constructed. The first time get() or a conversion operator is called, a new T (or derived) will be instantiated by a call to FactoryT::create(m_pod). The default type for FactoryT allocates a new instance of T passing the variable m_pod of type PODType to the constructor. The initialization is done in a thread safe manner. The double checked locking pattern is used, which doesn't have a large overhead.

No copy or assignment of LazyGlobal variables should ever be done. This cannot be enforced while maintaining the POD initialization of the class.

Conversion operators to T& and const T& are provided so that a LazyGlobal can be used wherever a T would be used.

All calls to get() or the conversion operators are thread safe.

Gotchas to be aware of:

  • This class does help a bit with the static deinitialization situation, because if the object has already been destroyed, it will be safely recreated if get() is called. However, if this happens, the destructor will not run again, and so the global variable will not be deleted.
  • Be careful to not use a function or constructor as an argument to BLOCXX_LAZY_GLOBAL_INIT. This will cause the initialization to happen during the dynamic initialization phase and negate the benefit of using LazyGlobal. If you erroneously use dynamic code, the compiler will not issue a warning or error.
Parameters
TThe type of the pointer.
PODTypeThe type of the POD data that can be passed to the constructor of T. This must be a POD type. If the compiler has a functional std::tr1::is_pod<>, then this will be enforced at compile time.
FactoryTTo create the T*, FactoryT::create() will be called with 1 parameter, the m_pod variable of type PODType. The return type must be convertible to a T*. The default DefaultVariableConstructorFactory will return a new T passing m_pod as a single argument to the constructor. The factory function should not access instances that may not be initialized, such as a dynamic global or static object, because the factory function may be run at any point during the dynamic initialization phase and there is no guarantee that the instance is already initialized. It is best to only refer to the POD data passed as an argument.

Definition at line 114 of file LazyGlobal.hpp.

Constructor & Destructor Documentation

◆ ~LazyGlobal()

template<typename T , typename PODType , typename FactoryT = DefaultVariableConstructorFactory<T, PODType>>
BLOCXX_NAMESPACE::LazyGlobal< T, PODType, FactoryT >::~LazyGlobal ( )
inline

Member Function Documentation

◆ get()

◆ getPtr()

template<typename T , typename PODType , typename FactoryT = DefaultVariableConstructorFactory<T, PODType>>
T * BLOCXX_NAMESPACE::LazyGlobal< T, PODType, FactoryT >::getPtr ( ) const
inlineprivate

◆ operator const T &()

template<typename T , typename PODType , typename FactoryT = DefaultVariableConstructorFactory<T, PODType>>
BLOCXX_NAMESPACE::LazyGlobal< T, PODType, FactoryT >::operator const T & ( ) const
inline

Definition at line 165 of file LazyGlobal.hpp.

◆ operator T&()

template<typename T , typename PODType , typename FactoryT = DefaultVariableConstructorFactory<T, PODType>>
BLOCXX_NAMESPACE::LazyGlobal< T, PODType, FactoryT >::operator T& ( )
inline

Definition at line 160 of file LazyGlobal.hpp.

◆ operator=()

template<typename T , typename PODType , typename FactoryT = DefaultVariableConstructorFactory<T, PODType>>
template<typename T2 >
T & BLOCXX_NAMESPACE::LazyGlobal< T, PODType, FactoryT >::operator= ( const T2 & rhs)
inline

Member Data Documentation

◆ m_onceFlag

template<typename T , typename PODType , typename FactoryT = DefaultVariableConstructorFactory<T, PODType>>
OnceFlag BLOCXX_NAMESPACE::LazyGlobal< T, PODType, FactoryT >::m_onceFlag
mutable

◆ m_p

template<typename T , typename PODType , typename FactoryT = DefaultVariableConstructorFactory<T, PODType>>
T* BLOCXX_NAMESPACE::LazyGlobal< T, PODType, FactoryT >::m_p
mutable

◆ m_pod

template<typename T , typename PODType , typename FactoryT = DefaultVariableConstructorFactory<T, PODType>>
PODType BLOCXX_NAMESPACE::LazyGlobal< T, PODType, FactoryT >::m_pod

The documentation for this class was generated from the following file: