#pragma once
#include <memory>
#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;
// constructor
explicit SmartPointer(value_type* p = nullptr) : core(new Core(p)) {
//
core->AddRef();
}
// copy constructor
SmartPointer(const SmartPointer& optr) : core(optr.core) { core->AddRef(); }
// move constructor
SmartPointer(SmartPointer&&) = default;
// copy assigment
SmartPointer& operator=(const SmartPointer&) = default;
// move assigment
SmartPointer& operator=(SmartPointer&& sp) {
if (this != &sp) {
if (core->Release() == 0) {
delete core;
}
core = sp.core;
core->AddRef();
}
return *this;
}
//
SmartPointer& operator=(value_type* other) {
core->p = other;
core->AddRef();
return *this;
}
~SmartPointer() {
if (core->Release() == 0) delete core;
}
// return reference to the object of class/type T
// if SmartPointer contains nullptr throw `SmartPointer::exception`
value_type& operator*() {
if (core->p == nullptr) throw exception();
return *core->p;
}
const value_type& operator*() const {
if (core->p == nullptr) throw exception();
auto const f = *core->p;
return f;
}
// return pointer to the object of class/type T
value_type* operator->() const { return core->p; }
value_type* get() const { return core->p; }
// if pointer == nullptr => return false
operator bool() const { return core->p != nullptr; }
// if pointers points to the same address or both null => true
template <typename U, typename AnotherAllocator>
bool operator==(const SmartPointer<U, AnotherAllocator>& pp) const {
return static_cast<void*>(core->p) == static_cast<void*>(pp.core->p);
}
// if pointers points to the same address or both null => false
template <typename U, typename AnotherAllocator>
bool operator!=(const SmartPointer<U, AnotherAllocator>& other) const {
return static_cast<void*>(other.core->p) != static_cast<void*>(core->p);
}
// if smart pointer contains non-nullptr => return count owners
// if smart pointer contains nullptr => return 0
std::size_t count_owners() const {
if (core->p == nullptr) return 0;
return core->c;
}
public:
class Core {
public:
value_type* p;
size_t c;
explicit Core(value_type* _p = nullptr) : p(_p), c(0) {}
void AddRef() { ++c; }
int Release() { return --c; }
~Core() {
if (p != nullptr) delete p;
}
};
Core* core;
};
} // namespace smart_pointer