#pragma once #include #include "Test.hpp" namespace smart_pointer { class exception : std::exception { using base_class = std::exception; using base_class::base_class; }; template class SmartPointer { ENABLE_CLASS_TESTS; public: using value_type = T; SmartPointer(value_type* ptr_ = nullptr) { if (ptr_ != nullptr) { core = new Core(ptr_); core->owners++; } else { core = nullptr; } } SmartPointer(const SmartPointer& other) { core = other.core; if (core != nullptr) core->owners++; } SmartPointer(SmartPointer&& other) : core(other.core) { other.core = nullptr; } SmartPointer& operator=(const SmartPointer& other) { if (core != nullptr) { if (core->owners > 1) core->owners--; else delete core; } core = other.core; if (core != nullptr) core->owners++; return *this; } SmartPointer& operator=(SmartPointer&& other) { other.core = nullptr; return *this; } SmartPointer& operator=(value_type* other) { if (core != nullptr) { if (core->owners > 1) core->owners--; else delete core; } if (other != nullptr) core = new Core(other); else core = nullptr; return *this; } ~SmartPointer() { if (core != nullptr) core = nullptr; } value_type& operator*() { if (core == nullptr) throw smart_pointer::exception(); return *core->ptr; } const value_type& operator*() const { if (core == nullptr) throw smart_pointer::exception(); return *core->ptr; } value_type* operator->() const { if (core != nullptr) return core->ptr; return nullptr; } value_type* get() const { if (core != nullptr) return core->ptr; return nullptr; } operator bool() const { if (core == nullptr) return false; return true; } template bool operator==(const SmartPointer& other) const { if (core != nullptr) return (core->ptr == reinterpret_cast(other.get())); else return (other.get() == nullptr); } template bool operator!=(const SmartPointer& other) const { if (*this == other) return false; return true; } std::size_t count_owners() const { if (core != nullptr) return core->owners; return 0; } private: class Core { public: explicit Core(value_type* ptr_) : ptr(ptr_) {} size_t owners = 0; value_type* ptr; }; Core* core; }; } // namespace smart_pointer