/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #ifndef LAZY_INIT #define LAZY_INIT #include #include #include #include namespace icinga { /** * Lazy object initialization abstraction inspired from * . * * @ingroup base */ template class LazyInit { public: inline LazyInit(std::function initializer = []() { return T(); }) : m_Initializer(std::move(initializer)) { m_Underlying.store(nullptr, std::memory_order_release); } LazyInit(const LazyInit&) = delete; LazyInit(LazyInit&&) = delete; LazyInit& operator=(const LazyInit&) = delete; LazyInit& operator=(LazyInit&&) = delete; inline ~LazyInit() { auto ptr (m_Underlying.load(std::memory_order_acquire)); if (ptr != nullptr) { delete ptr; } } inline T& Get() { auto ptr (m_Underlying.load(std::memory_order_acquire)); if (ptr == nullptr) { std::unique_lock lock (m_Mutex); ptr = m_Underlying.load(std::memory_order_acquire); if (ptr == nullptr) { ptr = new T(m_Initializer()); m_Underlying.store(ptr, std::memory_order_release); } } return *ptr; } private: std::function m_Initializer; std::mutex m_Mutex; std::atomic m_Underlying; }; } #endif /* LAZY_INIT */