#pragma once #include #include "Test.h" namespace smart_pointer { // `exception` class definition class exception : std::exception { using base_class = std::exception; using base_class::base_class; }; // `SmartPointer` class declaration template< typename T, typename Allocator > class SmartPointer { // don't remove this macro ENABLE_CLASS_TESTS; private: class Core; Core *core = nullptr; using zero = std::size_t; public: using value_type = T; explicit SmartPointer(value_type *p = nullptr) { if (!p) { core = nullptr; } else { core = new Core; core->refCount = {1}; core->ptr_ = p; } } // copy constructor SmartPointer(const SmartPointer &p) { if (core != nullptr) { if (core->refCount > 1) { core->refCount -= 1; } else { delete core->ptr_; delete core; core = new Core; } } core = p.core; if (core != nullptr) core->refCount++; } // move constructor SmartPointer(SmartPointer &&p) { if (core != nullptr) { if (core->refCount > 1) { core->refCount -= 1; } else { delete core->ptr_; delete core; core = new Core; } } core = p.core; if (p.core != nullptr) p.core = nullptr; } // copy assigment SmartPointer &operator=(const SmartPointer &p) { if (core != nullptr) { if (core->refCount > 1) { core->refCount--; } else { delete this->core->ptr_; delete this->core; core = nullptr; } } core = p.core; if (core != nullptr) core->refCount += 1; return *this; } // move assigment SmartPointer &operator=(SmartPointer &&p) { if (core != nullptr) { if (core->refCount > 1) { core->refCount--; } else { delete core->ptr_; delete core; } } core = p.core; (core ? p.core = nullptr : nullptr); return *this; } // SmartPointer &operator=(value_type *p) { if (core != nullptr) { if (core->refCount > 1) { core->refCount--; } else { delete core->ptr_; delete core; core = new Core; } } else { core = new Core; } if (p != nullptr) { core->ptr_ = p; } else { delete core; core = {nullptr}; } if (core) core->refCount = {1}; return *this; } ~SmartPointer() { if (!core) { delete core; } else if (core->refCount > 1) { core->refCount -= 1; } else { if (core->ptr_ != nullptr) delete core->ptr_; delete core; } } // return reference to the object of class/type T // if SmartPointer contains nullptr throw `SmartPointer::exception` value_type &operator*() { if (!get()) throw exception(); else return *core->ptr_; } const value_type &operator*() const { if (get() == nullptr) { throw exception(); } else { return *core->ptr_; } } // return pointer to the object of class/type T value_type *operator->() const { return core ? core->ptr_ : nullptr; } value_type *get() const { if (core != nullptr) core->ptr_; return nullptr; } // if pointer == nullptr => return false operator bool() const { return core == nullptr; } // if pointers points to the same address or both null => true template bool operator==(const SmartPointer &p) const { return !(*this != p); } // if pointers points to the same address or both null => false template bool operator!=(const SmartPointer &p) const { return !((p.get() == nullptr && get() == nullptr) || (p.get() != nullptr && get() != nullptr && *p.get() == *get() && static_cast(p.get()) == static_cast(get()))); } // if smart pointer contains non-nullptr => return count owners // if smart pointer contains nullptr => return 0 std::size_t count_owners() const { if (core) return core->refCount; return zero(0); } private: class Core { public: value_type *ptr_; zero refCount{0}; }; }; } //namespace smart_pointer