#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Test.hpp" using std::size_t; namespace smart_pointer { class exception : std::exception { using base_class = std::exception; using base_class::base_class; }; template < typename T, typename Allocator > class SmartPointer { ENABLE_CLASS_TESTS; public: using value_type = T; explicit SmartPointer(value_type* x = nullptr) { if (x != nullptr) { core = new Core(x); core->c++; } else { core = nullptr; } } SmartPointer(const SmartPointer& oth) { core = oth.core; if (core != nullptr) { core->c++; } } SmartPointer(SmartPointer&& oth) noexcept { core = oth.core; oth.core = nullptr; } SmartPointer &operator=(const SmartPointer& oth) { if (core != nullptr) { if (core->c > 1) { core->c--; } else { delete (core); } } core = oth.core; if (core != nullptr) { oth.core->c++; } return *this; } SmartPointer &operator=(SmartPointer&& oth) { core = oth.core; delete oth.core->p; oth.core = nullptr; return *this; } SmartPointer &operator=(value_type* oth) { if (core != nullptr) { if (core->c > 1) { core->c--; } else { delete(core); } } if (oth != nullptr) { core = new Core(oth); } else { core = nullptr; } return *this; } ~SmartPointer() { if (core != nullptr) { core = nullptr; } } value_type& operator*() { if (core == nullptr) { throw smart_pointer::exception(); } return *core->p; } const value_type& operator*() const { if (core == nullptr) { throw smart_pointer::exception(); } return *core->p; } value_type* operator->() const { if (core != nullptr) { return core->p; } return nullptr; } value_type* get() const { if (core != nullptr) { return core->p; } return nullptr; } explicit operator bool() const { return (core != nullptr); } template bool operator==(const SmartPointer& oth) const { if (core != nullptr) { return (core->p == reinterpret_cast(oth.get())); } else { return (oth.get() == nullptr); } } template bool operator!=(const SmartPointer& oth) const { return !(*this == oth); } size_t count_owners() const { if (core == nullptr) { return 0; } return core->c; } private: class Core { public: explicit Core(value_type* x) : p(x) {} size_t c = 0; value_type* p; }; Core* core; }; } // namespace smart_pointer