先放代码
只实现了基础功能,基本用法和智能指针相差不大,提供了UniquePtr转std::unique_ptr的方法,提供了删除器
#pragma once
#include <memory> /* For std::move, std::forward, std::unique_ptr */
#include <utility> /* For std::exchange */
#include <type_traits> /* For template check */
#include <atomic> /* For std::atomic */
/* Deleter, details see std::default_delete<T> */
namespace csp {
template<typename T>
class DefaultDeleter {
public:
constexpr DefaultDeleter() noexcept = default;
virtual ~DefaultDeleter() noexcept = default;
template<typename U, std::enable_if_t<std::is_convertible_v<U*, T*>, int> = 0>
DefaultDeleter(const DefaultDeleter<U>&) noexcept {}
/* Call for delete */
void operator()(T* p) const noexcept {
delete p;
p = nullptr;
}
/* Compatible std deleter */
operator std::default_delete<T>() const noexcept {
return std::default_delete<T>();
}
};
/* Used for array */
template<typename T>
class DefaultDeleter<T[]> {
public:
constexpr DefaultDeleter() noexcept = default;
virtual ~DefaultDeleter() noexcept = default;
template<typename U, std::enable_if_t<std::is_convertible_v<U(*)[], T(*)[]>, int> = 0>
DefaultDeleter(const DefaultDeleter<U[]>&) noexcept {}
/* Call for delete */
void operator()(T* p) const noexcept {
delete[] p;
}
/* Compatible std deleter */
operator std::default_delete<T[]>() const noexcept {
return std::default_delete<T[]>();
}
};
}
/* Unique pointer */
namespace csp {
template<typename T, typename D = DefaultDeleter<T>>
class UniquePtr final {
using ElementType = T;
using Pointer = ElementType*;
using DeleterType = D;
private:
Pointer ptr;
DeleterType deleter;
public:
/* Constructor */
constexpr UniquePtr(Pointer p) noexcept : ptr(p) {}
constexpr UniquePtr(Pointer p, DeleterType& deleter) noexcept : ptr(p), deleter(std::forward(deleter)) {}
constexpr UniquePtr(void) noexcept : ptr(nullptr) {}
constexpr UniquePtr(std::nullptr_t) noexcept : ptr(nullptr) {}
constexpr UniquePtr(const UniquePtr<T, D>&) noexcept = delete; // Disable the copy constructor
constexpr UniquePtr(UniquePtr<T, D>&& up) noexcept : ptr(up.release()), deleter(up.getDeleter()) {}
/* Deconstructor */
~UniquePtr() noexcept {
if (ptr) { deleter(ptr); }
}
/* Operators */
UniquePtr<T, D>& operator=(const UniquePtr<T, D>&) noexcept = delete; // Disable the copy assignment operator
UniquePtr<T, D>& operator=(UniquePtr<T, D>&& rhs) noexcept {
if ((&rhs) != this) {
reset(rhs.release());
deleter = rhs.getDeleter();
}
return *this;
};
Pointer operator->() const noexcept { return ptr; } // UniquePtr<T> upt; upt->;
ElementType& operator*() const noexcept { return *ptr; } // UniquePtr<T> upt; (*upt).;
/* Functions */
Pointer get() const noexcept { return ptr; }
DeleterType getDeleter() noexcept { return static_cast<const UniquePtr<T, D>&>(*this).getDeleter(); }
const DeleterType& getDeleter() const noexcept { return deleter; }
Pointer release() noexcept { return std::exchange(ptr, nullptr); }
void swap(UniquePtr<T, D>& p) noexcept { std::swap(ptr, p.ptr); } // not swap the deleter
void reset(Pointer p = nullptr) noexcept {
if (nullptr == p) { return; }
if (ptr) { deleter(ptr); }
std::swap(ptr, p);
}
/* If you want to call this function, you must make sure that your deleter can transorm to std::default_deleter<T> */
std::unique_ptr<T, D> toStdUniquePtr() {
return std::unique_ptr<T, D>(release(), deleter);
}
};
template<typename T, typename D = DefaultDeleter<T>, typename ...Args>
UniquePtr<T, D> makeUnique(Args&&... args) {
return UniquePtr<T, D>(new T(std::forward<Args>(args)...));
}
}
/* Shared pointer */
namespace csp {
class CounterBase {
public:
virtual ~CounterBase() {}
virtual void incRefCount() noexcept = 0;
virtual void incWeakRefCount() noexcept = 0;
virtual void decRefCount() noexcept = 0;
virtual void decWeakRefCount() noexcept = 0;
virtual long useCount() const noexcept = 0;
virtual bool unique() const noexcept = 0;
virtual long weakUseCount() const noexcept = 0;
virtual bool expired() const noexcept = 0;
virtual void* getDeleter() noexcept = 0;
};
template<typename T, typename D = DefaultDeleter<T>>
class Counter : public CounterBase {
using ElementType = T;
using Pointer = ElementType*;
using DeleterType = D;
private:
std::atomic_long _useCount;
std::atomic_long _weakUseCount;
Pointer ptr;
DeleterType deleter;
public:
constexpr Counter(Pointer p) :
_useCount(1),
_weakUseCount(1),
ptr(p),
deleter{} {}
constexpr Counter(Pointer p, DeleterType deleter) :
_useCount(1),
_weakUseCount(1),
ptr(p),
deleter(std::forward(deleter)) {}
virtual ~Counter() {}
/* Overrides */
virtual void incRefCount() noexcept { ++_useCount; }
virtual void incWeakRefCount() noexcept { ++_weakUseCount; }
virtual void decRefCount() noexcept {
--_useCount;
if (0 == _useCount) {
if (ptr) {
deleter(ptr);
}
decWeakRefCount();
}
}
virtual void decWeakRefCount() noexcept {
--_weakUseCount;
if (0 == _weakUseCount) {
delete this;
}
}
virtual long useCount() const noexcept { return _useCount; }
virtual bool unique() const noexcept { return 1 == _useCount; }
virtual long weakUseCount() const noexcept { return _weakUseCount - (_useCount ? 1 : 0); }
virtual bool expired() const noexcept { return 0 == _useCount; }
virtual void* getDeleter() noexcept { return reinterpret_cast<void*>(std::addressof(deleter)); }
};
template<typename T, typename D = DefaultDeleter<T>>
class SharedPtr;
template<typename T, typename D = DefaultDeleter<T>>
class WeakPtr final {
// using ElementType = std::remove_extent<T>::type;
using ElementType = T;
using Pointer = ElementType*;
using DeleterType = D;
private:
Pointer ptr;
CounterBase* counter;
public:
friend class SharedPtr<T, D>;
/* Constructors */
constexpr WeakPtr(void) noexcept :
ptr(nullptr),
counter(nullptr) {}
WeakPtr(const SharedPtr<T, D>& sp) noexcept :
ptr(sp.ptr),
counter(sp.counter) {
if (counter) {
counter->incWeakRefCount();
}
}
WeakPtr(const WeakPtr<T, D>* wp) noexcept :
ptr(wp.ptr),
counter(wp.counter) {
if (counter) {
counter->incWeakRefCount();
}
}
/* Deconstructor */
~WeakPtr() {
if (counter) {
counter->decWeakRefCount();
}
}
/* Operators */
WeakPtr<T, D>& operator=(const WeakPtr<T, D>& wp) noexcept {
const_cast<WeakPtr<T, D>&>(wp).swap(*this);
return *this;
}
WeakPtr<T, D>& operator=(const SharedPtr<T, D>& sp) noexcept {
/* First, use static_cast to change sp to wp, <const SharedPtr<T, D>&> -> <const WeakPtr<T, D>&> */
/* Second, use const_cast to remove const, <const WeakPtr<T, D>&> -> <WeakPtr<T, D>&> */
const_cast<WeakPtr<T, D>&>(static_cast<const WeakPtr<T, D>&>(sp)).swap(*this);
return *this;
}
/* Functions */
void swap(WeakPtr<T, D>& wp) noexcept {
std::swap(ptr, wp.ptr);
std::swap(counter, wp.counter);
}
void reset() noexcept { WeakPtr<T, D>().swap(*this); }
long useCount() const noexcept { return counter ? counter->useCount() : 0; }
bool expired() const noexcept { return counter ? counter->expired() : false; }
SharedPtr<T, D> lock() const noexcept { return SharedPtr<T, D>(expired() ? nullptr : *this); }
};
template<typename T, typename D = DefaultDeleter<T>>
class SharedPtr final {
using ElementType = T;
using Pointer = ElementType*;
using DeleterType = D;
private:
Pointer ptr;
CounterBase* counter;
public:
friend class WeakPtr<T, D>;
/* Constructor */
constexpr SharedPtr(void) noexcept :
ptr(nullptr),
counter(nullptr) {}
constexpr SharedPtr(std::nullptr_t) noexcept :
ptr(nullptr),
counter(nullptr) {}
constexpr SharedPtr(std::nullptr_t p, DeleterType deleter) noexcept :
ptr(nullptr),
counter(new Counter<T, D>(p, deleter)) {}
constexpr SharedPtr(Pointer p) noexcept :
ptr(p),
counter(new Counter<T, D>(p)) {}
constexpr SharedPtr(Pointer p, DeleterType deleter) noexcept :
ptr(p),
counter(new Counter<T, D>(p, deleter)) {}
SharedPtr(const SharedPtr<T, D>& sp) noexcept :
ptr(sp.ptr),
counter(sp.counter) {
if (counter) {
counter->incRefCount();
}
}
SharedPtr(SharedPtr<T, D>&& sp) noexcept :
ptr(std::exchange(sp.ptr, nullptr)),
counter(std::exchange(sp.counter, nullptr)) {}
SharedPtr(const WeakPtr<T, D>& wp) noexcept(false) :
ptr(wp.ptr),
counter(wp.counter) {
if (wp.expired()) {
/* Compatible with std error */
throw std::bad_weak_ptr();
}
counter->incRefCount();
}
/* Deconstructor */
~SharedPtr() {
if (counter) {
counter->decRefCount();
}
}
/* Operators */
SharedPtr<T, D>& operator=(const SharedPtr<T, D>& sp) noexcept {
const_cast<SharedPtr<T, D>&>(sp).swap(*this);
return *this;
}
SharedPtr<T, D>& operator=(SharedPtr<T, D>&& sp) noexcept {
const_cast<SharedPtr<T, D>&>(std::move(sp)).swap(*this);
return *this;
}
Pointer operator->() const noexcept { return ptr; } // UniquePtr<T> upt; upt->;
ElementType& operator*() const noexcept { return *ptr; } // UniquePtr<T> upt; (*upt).;
/* Functions */
void swap(SharedPtr<T, D>& sp) noexcept {
std::swap(ptr, sp.ptr);
std::swap(counter, sp.counter);
}
void reset() noexcept { SharedPtr<T, D>().swap(*this); }
Pointer get() const noexcept { return ptr; }
long useCount() const noexcept { return counter ? counter->useCount() : 0; }
bool unique() const noexcept { return counter ? counter->unique() : false; }
};
template<typename T, typename D = DefaultDeleter<T>, typename ...Args>
SharedPtr<T, D> makeShared(Args&&... args) {
return SharedPtr<T, D>(new T(std::forward<Args>(args)...));
}
}