/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #ifndef LAZY_INIT #define LAZY_INIT #include "base/atomic.hpp" #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)) { } 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; Atomic m_Underlying {nullptr}; }; } #endif /* LAZY_INIT */