#pragma once #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; }; // `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* ptr = nullptr) { if (ptr != nullptr) { this->core = new Core(ptr); } else { core = nullptr; } } // copy constructor SmartPointer(const SmartPointer& otherPointer) { // changeOwners(-1); this->core = otherPointer.core; changeOwners(1); } // move constructor SmartPointer(SmartPointer&& oldPointer) { this->core = oldPointer.core; oldPointer.changeOwners(-1); oldPointer.core = nullptr; } // copy assigment SmartPointer& operator=(const SmartPointer& otherPointer) { changeOwners(-1); this->core = otherPointer.core; changeOwners(1); return *this; } // move assigment SmartPointer& operator=(SmartPointer&& oldPointer) { changeOwners(-1); this->core = oldPointer.core; oldPointer.core = nullptr; return *this; } // SmartPointer& operator=(value_type* ptr) { if (ptr != nullptr) { changeOwners(-1); this->core = new Core(ptr); } else { this->core = nullptr; } return *this; } ~SmartPointer() { if (this->core != nullptr) { if (this->core->count_owners == 1) { delete core; } else { this->core->count_owners -= 1; } } else { delete core; } } // return reference to the object of class/type T // if SmartPointer contains nullptr throw `SmartPointer::exception` value_type& operator*() { if (this->core == nullptr) { throw exception("dfs"); } else { return *(this->core->ptr); } } value_type& operator*() const { if (this->core== nullptr) { throw exception("fgr"); } else { return *(this->core->ptr); } } // return pointer to the object of class/type T value_type* operator->() const { if (core == nullptr) return nullptr; return this->core->ptr; } value_type* get() const { if (core == nullptr) return nullptr; return this->core->ptr; } // if pointer == nullptr => return false operator bool() const { if (this->core == nullptr) { return false; } else { return true; } } // if pointers points to the same address or both null => true template bool operator==(const SmartPointer& otherPointer) const { return int(this->core) == int(otherPointer.core); return false; } // if pointers points to the same address or both null => false template bool operator!=(const SmartPointer& otherPointer) const { return int(this->core) != int(otherPointer.core); } // 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) return 0; return this->core->count_owners; } class Core { public: T* ptr; int64_t count_owners; explicit Core(T* ptr) { this->ptr = ptr; if (ptr != nullptr) { count_owners = 1; } else { count_owners = 0; } } bool operator==(const Core& other_core) { if (typeid(ptr) != typeid(other_core.ptr)) return false; return this->ptr == other_core.ptr; } bool operator!=(const Core& other_core) { if (typeid(ptr) == typeid(other_core.ptr)) { return this->ptr != other_core.ptr; } return true; } }; Core* core; private: void changeOwners(int value = 1) { if (this->core != nullptr) { if (this->core->ptr != nullptr) { this->core->count_owners += value; } } } }; } // namespace smart_pointer