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