#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* xPtr = nullptr) : core((xPtr == nullptr ? nullptr : new Core(xPtr))) { } // copy constructor SmartPointer(const SmartPointer& other) : core(other.core != nullptr ? other.core : nullptr) { if (core != nullptr) { this->core->owners++; } } // move constructor SmartPointer(SmartPointer&& other) : core(std::exchange(other.core, nullptr)) { } // copy assigment SmartPointer& operator=(const SmartPointer& other) { this->~SmartPointer(); this->core = other.core; if (this->core != nullptr) this->core->owners++; return *this; } // move assigment 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->owners <= 1) { delete this->core; } else { this->core->owners--; } } } // 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->valPtr == nullptr) { throw smart_pointer::exception(); } else { return *(this->core->valPtr); } } const value_type& operator*() const { if (this->core == nullptr || this->core->valPtr == nullptr) { throw smart_pointer::exception(); } return *(this->core->valPtr); } // return pointer to the object of class/type T value_type* operator->() const { return this->get(); } value_type* get() const { if (this->core == nullptr) { return nullptr; } else { return this->core->valPtr; } } // if pointer == nullptr => return false operator bool() const { if (this->core == nullptr || this->core->valPtr == nullptr) { return false; } else { return true; } } decltype(auto) getCore() const { return static_cast(this->core); } // if pointers points to the same address or both null => true template bool operator==(const SmartPointer& other) const { return this->getCore() == other.getCore(); } // if pointers points to the same address or both null => false template bool operator!=(const SmartPointer& other) const { return !(SmartPointer::operator==(other)); } // 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; } else { return this->core->owners; } } private: class Core { public: explicit Core(value_type* x) : valPtr(x), owners(1) { } ~Core() { if (valPtr != nullptr) delete valPtr; } value_type* valPtr; std::size_t owners; }; Core* core; }; };