#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(p); } } // copy constructor SmartPointer(const SmartPointer& other) : core(other.core) { if (other.core != nullptr) core->count++; } // move constructor SmartPointer(SmartPointer&& other) : core(other.core) { other = nullptr; } // copy assigment SmartPointer& operator=(const SmartPointer& other) { if (&other == this) return *this; if (core != nullptr) { core->count -= 1; if (core->count == 0) { delete core; } } core = other.core; if (other.core != nullptr) { core->count++; } return *this; } // move assigment SmartPointer& operator=(SmartPointer&& other) { if (&other == this) return *this; if (core != nullptr) { core->count -= 1; if (core->count == 0) { delete core; } } core = other.core; other.core = nullptr; return *this; } // SmartPointer& operator=(value_type* p) { if (core != nullptr) { core->count -= 1; if (core->count == 0) { delete core; } } if (p != nullptr) core = new Core(p); else { core = nullptr; } return *this; } ~SmartPointer() { } // return reference to the object of class/type T // if SmartPointer contains nullptr throw `SmartPointer::exception` value_type& operator*() { if (core != nullptr) return *(core->p); throw smart_pointer::exception(); } const value_type& operator*() const { if (core != nullptr) return *(core->p); throw smart_pointer::exception(); } // return pointer to the object of class/type T value_type* operator->() const { if (core != nullptr) return core->p; return nullptr; } value_type* get() const { if (core != nullptr) return core->p; 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& other) const { return ((void*)this->get() == (void*)other.get() || (!this && !other)); } // if pointers points to the same address or both null => false template bool operator!=(const SmartPointer& other) const { return !((void*)this->get() == (void*)other.get() || (!this && !other)); } // 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; else return core->count; }; private: class Core { public: value_type* p; std::size_t count; Core(value_type* ptr) : p(ptr), count(1) {} ~Core() { Allocator a; a.deallocate(p, sizeof(value_type)); p = nullptr; } value_type get() { return *p; } }; Core* core; }; }