#pragma once #include #include "Test.hpp" 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; public: using value_type = T; explicit SmartPointer(value_type *p = nullptr) { if (p == nullptr) { core = nullptr; } else { core = new Core; core->count_pointers_ = 1; core->pointer_ = p; } } // copy constructor SmartPointer(const SmartPointer &smartPointer) { core = new Core; core = smartPointer.core; if (core != nullptr) core->count_pointers_++; } // move constructor SmartPointer(SmartPointer &&smartPointer) : core(smartPointer.core) { smartPointer.core = nullptr; } // copy assigment SmartPointer &operator=(const SmartPointer &smartPointer) { if (core != nullptr) { if (core->count_pointers_ > 1) core->count_pointers_--; } delete core; core = new Core; core = smartPointer.core; if (core != nullptr) core->count_pointers_++; return *this; } // move assigment SmartPointer &operator=(SmartPointer &&smartPointer) { if (core != nullptr) { if (core->count_pointers_ > 1) core->count_pointers_--; } delete core; core = smartPointer.core; smartPointer.core = nullptr; return *this; } // SmartPointer &operator=(value_type *p) { if (p == nullptr) { core = nullptr; } else { core = new Core; core->count_pointers_ = 1; core->pointer_ = p; } return *this; } ~SmartPointer() { if (core != nullptr) { core->count_pointers_--; } } // return reference to the object of class/type T // if SmartPointer contains nullptr throw `SmartPointer::exception` value_type &operator*() { if (core == nullptr) { throw smart_pointer::exception(); } return *core->pointer_; } const value_type &operator*() const { if (core == nullptr) { throw smart_pointer::exception(); } return *core->pointer_; } // return pointer to the object of class/type T value_type *operator->() const { if (core == nullptr) { return nullptr; } return core->pointer_; } value_type *get() const { if (core == nullptr) { return nullptr; } return core->pointer_; } // 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 & x) const { if (x.get() == nullptr && this->get() == nullptr) { return true; } return static_cast(x.get()) == static_cast(this->get()); } // if pointers points to the same address or both null => false template bool operator!=(const SmartPointer & x) const { if (x.get() == nullptr && this->get() == nullptr) { return false; } else if (x.get() == nullptr || this->get() == nullptr) { return true; } return static_cast(x.get()) != static_cast(this->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 == nullptr) { return 0; } return core->count_pointers_; } private: class Core { public: std::size_t count_pointers_; value_type* pointer_; }; Core *core; }; } // namespace smart_pointer