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