#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Test.hpp" 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* xPtr = nullptr) : core((xPtr == nullptr ? nullptr : new Core(xPtr))) { } SmartPointer(const SmartPointer& other) : core(other.core != nullptr ? other.core : nullptr) { if (core != nullptr) { this->core->c++; } } SmartPointer(SmartPointer&& other) : core(std::exchange(other.core, nullptr)) { } SmartPointer& operator=(const SmartPointer& other) { this->~SmartPointer(); this->core = other.core; if (this->core != nullptr) { this->core->c++; } return *this; } SmartPointer& operator=(SmartPointer&& other) { this->~SmartPointer(); this->core = std::move(other.core); other.core = nullptr; return *this; } SmartPointer& operator=(value_type* p) { this->~SmartPointer(); if (p == nullptr) { this->core = nullptr; } else { this->core = new Core(p); } return *this; } ~SmartPointer() { if (this->core != nullptr) { if (this->core->c <= 1) { delete this->core; } else { this->core->c--; } } } value_type& operator*() { if (this->core == nullptr || this->core->val == nullptr) { throw smart_pointer::exception(); } else { return *(this->core->val); } } const value_type& operator*() const { if (this->core == nullptr || this->core->val == nullptr) { throw smart_pointer::exception(); } return *(this->core->val); } value_type* operator->() const { return this->get(); } value_type* get() const { if (this->core == nullptr) { return nullptr; } else { return this->core->val; } } operator bool() const { if (this->core == nullptr || this->core->val == nullptr) { return false; } else { return true; } } decltype(auto) getCore() const { return static_cast(this->core); } template bool operator==(const SmartPointer& other) const { return this->getCore() == other.getCore(); } template bool operator!=(const SmartPointer& other) const { return !(SmartPointer::operator==(other)); } std::size_t count_owners() const { if (this->core == nullptr) { return 0; } else { return this->core->c; } } private: class Core { public: explicit Core(value_type* x) : val(x), c(1) {} ~Core() { if (val != nullptr) delete val; } value_type* val; std::size_t c; }; Core* core; }; }; // namespace smart_pointer