#pragma once #include namespace vlc { template class IntrusivePtr { public: IntrusivePtr() noexcept = default; IntrusivePtr(T* ptr, bool own = true) : m_ptr(ptr) { if (own) { intrusiveIncRef(m_ptr); } } IntrusivePtr(const IntrusivePtr& src) { *this = src; } IntrusivePtr& operator = (const IntrusivePtr& src) { intrusiveDecRef(m_ptr); m_ptr = src.m_ptr; intrusiveIncRef(m_ptr); return *this; } template IntrusivePtr(const IntrusivePtr& src) { *this = src; } template IntrusivePtr& operator = (const IntrusivePtr& src) { static_assert(std::is_base_of::value, "Type of source pointer should be derived from this type"); intrusiveDecRef(m_ptr); m_ptr = static_cast(src.get()); intrusiveIncRef(m_ptr); return *this; } IntrusivePtr(IntrusivePtr&& src) { swap(src); } IntrusivePtr& operator = (IntrusivePtr&& src) { swap(src); return *this; } ~IntrusivePtr() { intrusiveDecRef(m_ptr); } explicit operator bool() const { return get() != nullptr; } void swap(IntrusivePtr& r) { std::swap(m_ptr, r.m_ptr); } void reset(T* ptr = nullptr, bool own = true) { IntrusivePtr(ptr, own).swap(*this); } T* operator -> () const { assert(m_ptr); return m_ptr; } T& operator * () const { assert(m_ptr); return *m_ptr; } T* release() { T* result = nullptr; std::swap(result, m_ptr); intrusiveDecRef(result); return result; } T* get() const { return m_ptr; } template DerivedType* cast() { return static_cast(m_ptr); } template const DerivedType* cast() const { return static_cast(m_ptr); } private: T* m_ptr = nullptr; }; template IntrusivePtr make_intrusive(Args&&... args) { return IntrusivePtr(new T(std::forward(args)...)); } }