#pragma once
#include <memory>
#include <type_traits>
namespace smart_pointer {
class exception : std::exception {
using base_class = std::exception;
using base_class::base_class;
};
template<typename T, typename Allocator>
class SmartPointer {
public:
using value_type = T;
private:
value_type *value_;
std::size_t count_owners_;
public:
explicit SmartPointer(value_type *value = nullptr) {
if (value != nullptr)
core = new Core(value);
else
core = nullptr;
}
SmartPointer(const SmartPointer &A) {
core = A.core;
if (*this)
core->Increment();
}
SmartPointer(SmartPointer &&A) {
core = A.core;
A.core = nullptr;
}
SmartPointer &operator=(const SmartPointer &A) {
this->~SmartPointer();
core = A.core;
if (*this)
core->Increment();
return *this;
}
SmartPointer &operator=(SmartPointer &&A) {
this->~SmartPointer();
core = A.core;
A.core = nullptr;
return *this;
}
SmartPointer &operator=(value_type *A) {
this->~SmartPointer();
if (A != nullptr)
core = new Core(A);
else
core = nullptr;
return *this;
}
~SmartPointer() {
if (*this) {
core->Decrement();
if (core->CountOwners() == 0)
delete core;
}
}
value_type &operator*() {
if (!*this)
throw smart_pointer::exception();
return *(core->Value());
}
const value_type &operator*() const {
if (!*this)
throw smart_pointer::exception();
return *(core->Value());
}
value_type *operator->() const {
if (*this)
return core->Value();
return nullptr;
}
value_type *get() const {
if (*this)
return core->Value();
return nullptr;
}
operator bool() const {
return !(core == nullptr || core->Value() == nullptr);
}
template<typename U, typename AnotherAllocator>
bool operator==(const SmartPointer<U, AnotherAllocator> &A) const {
if (!*this && !A)
return true;
if (!std::is_same<T, U>::value)
return false;
return reinterpret_cast<void *>(get()) ==
reinterpret_cast<void *>(A.get());
}
template<typename U, typename AnotherAllocator>
bool operator!=(const SmartPointer<U, AnotherAllocator> &A) const {
if (!*this && !A)
return false;
if (!std::is_same<T, U>::value)
return true;
return reinterpret_cast<void *>(get()) !=
reinterpret_cast<void *>(A.get());
}
std::size_t count_owners() const {
if (*this)
return core->CountOwners();
return 0;
}
private:
class Core {
public:
explicit Core(value_type *value) : value_(value), count_owners_(0) {
Increment();
}
~Core() {
delete value_;
value_ = nullptr;
}
value_type *Value() {
return value_;
}
value_type *Value() const {
return value_;
}
void Increment() {
count_owners_++;
}
void Decrement() {
count_owners_--;
}
std::size_t CountOwners() const {
return count_owners_;
}
};
Core *core;
};
} // namespace smart_pointer