#pragma once #include #include #include "nf7.hh" namespace nf7 { class LifeExpiredException final : public nf7::Exception { public: using nf7::Exception::Exception; }; template class Life final { public: class Ref; Life() = delete; Life(T& target) noexcept : ptr_(&target) { } ~Life() noexcept { if (data_) data_->ptr = nullptr; } Life(const Life&) = delete; Life(Life&&) = delete; Life& operator=(const Life&) = delete; Life& operator=(Life&&) = delete; private: T* const ptr_; struct Data final { T* ptr; }; std::shared_ptr data_; }; template class Life::Ref final { public: Ref() = default; Ref(const Life& life) noexcept { if (!life.data_) { auto& l = const_cast(life); l.data_ = std::make_shared(); l.data_->ptr = l.ptr_; } data_ = life.data_; } Ref(const Ref&) = default; Ref(Ref&&) = default; Ref& operator=(const Ref&) = default; Ref& operator=(Ref&&) = default; void EnforceAlive() const { if (!data_->ptr) { throw LifeExpiredException {"target expired"}; } } operator bool() const noexcept { return !!data_->ptr; } T& operator*() const noexcept { assert(data_->ptr); return *data_->ptr; } T* operator->() const noexcept { return &**this; } private: std::shared_ptr data_; }; } // namespace nf7