#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;
private:
class Core;
Core *core = nullptr;
using zero = std::size_t;
public:
using value_type = T;
explicit SmartPointer(value_type *p = nullptr) {
if (!p) {
core = nullptr;
} else {
core = new Core;
core->refCount = {1};
core->ptr_ = p;
}
}
// copy constructor
SmartPointer(const SmartPointer &p) {
if (core != nullptr) {
if (core->refCount > 1) {
core->refCount -= 1;
} else {
delete core->ptr_;
delete core;
core = new Core;
}
}
core = p.core;
if (core != nullptr)
core->refCount++;
}
// move constructor
SmartPointer(SmartPointer &&p) {
if (core != nullptr) {
if (core->refCount > 1) {
core->refCount -= 1;
} else {
delete core->ptr_;
delete core;
core = new Core;
}
}
core = p.core;
if (p.core != nullptr)
p.core = nullptr;
}
// copy assigment
SmartPointer &operator=(const SmartPointer &p) {
if (core != nullptr) {
if (core->refCount > 1) {
core->refCount--;
} else {
delete this->core->ptr_;
delete this->core;
core = nullptr;
}
}
core = p.core;
if (core != nullptr)
core->refCount += 1;
return *this;
}
// move assigment
SmartPointer &operator=(SmartPointer &&p) {
if (core != nullptr) {
if (core->refCount > 1) {
core->refCount--;
} else {
delete core->ptr_;
delete core;
}
}
core = p.core;
(core ? p.core = nullptr : nullptr);
return *this;
}
//
SmartPointer &operator=(value_type *p) {
if (core != nullptr) {
if (core->refCount > 1) {
core->refCount--;
} else {
delete core->ptr_;
delete core;
core = new Core;
}
} else {
core = new Core;
}
if (p != nullptr) {
core->ptr_ = p;
} else {
delete core;
core = {nullptr};
}
if (core)
core->refCount = {1};
return *this;
}
~SmartPointer() {
if (!core) {
delete core;
} else if (core->refCount > 1) {
core->refCount -= 1;
} else {
if (core->ptr_ != nullptr)
delete core->ptr_;
delete core;
}
}
// return reference to the object of class/type T
// if SmartPointer contains nullptr throw `SmartPointer::exception`
value_type &operator*() {
if (!get())
throw exception();
else
return *core->ptr_;
}
const value_type &operator*() const {
if (get() == nullptr) {
throw exception();
} else {
return *core->ptr_;
}
}
// return pointer to the object of class/type T
value_type *operator->() const {
return core ? core->ptr_ : nullptr;
}
value_type *get() const {
if (core != nullptr)
core->ptr_;
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<typename U, typename AnotherAllocator>
bool operator==(const SmartPointer<U, AnotherAllocator> &p) const {
return !(*this != p);
}
// if pointers points to the same address or both null => false
template<typename U, typename AnotherAllocator>
bool operator!=(const SmartPointer<U, AnotherAllocator> &p) const {
return !((p.get() == nullptr && get() == nullptr) ||
(p.get() != nullptr && get() != nullptr &&
*p.get() == *get() &&
static_cast<void *>(p.get()) ==
static_cast<void *>(get())));
}
// if smart pointer contains non-nullptr => return count owners
// if smart pointer contains nullptr => return 0
std::size_t count_owners() const {
if (core)
return core->refCount;
return zero(0);
}
private:
class Core {
public:
value_type *ptr_;
zero refCount{0};
};
};
} // namespace smart_pointer