智能指针 “memory.h”
几个常见的智能指针:
1. auto_ptr
参考链接:https://github.com/Alinshans/MyTinySTL/blob/master/MyTinySTL/memory.h
可以使用unique_ptr替换auto_ptr的功能
其中,并没有类似于unique_ptr、shared_ptr、weak_ptr的判断初始化和赋值时类型不同带来的问题
//------------------------------------------------------------------
// 模板类: auto_ptr
// 一个具有严格对象所有权的小型智能指针
// 用unique_ptr替代
template<typename T>
class auto_ptr {
public:
using element_type = T;
private:
T* ptr; // raw pointer
public:
explicit auto_ptr(T* p = nullptr) : ptr(p) {}
auto_ptr(auto_ptr& rhs) :ptr(rhs.release()) {}
template<typename U>
auto_ptr(auto_ptr<U>& rhs) : ptr(rhs.release()) {}
auto_ptr& operator=(auto_ptr& rhs) {
if (this != &rhs) {
delete ptr;
ptr = rhs.release();
}
return *this;
}
template<typename U>
auto_ptr& operator=(auto_ptr<U>& rhs) {
if (this->get() != rhs.get()) {
delete ptr;
ptr = rhs.release();
}
return *this;
}
~auto_ptr() { delete ptr; }
public:
T& operator*() { return *ptr; }
T* operator->() { return ptr; }
// 获得指针
T* get() const {
return ptr;
}
// 释放指针
T* release() {
T* tmp = ptr;
ptr = nullptr;
return tmp;
}
// 重置指针
void reset(T* p = nullptr) {
if (ptr != p) {
delete ptr;
ptr = p;
}
}
};
2. unique_ptr
指针实现都参照https://github.com/RRRadicalEdward/smart_pointers/blob/master/
主要代码在重载运算符,以及数组类型的特例
pointers_are_convertible用于判断FROM和TO类型指针是否可以转化
template<typename FROM, typename TO>
using pointers_are_convertible = std::enable_if_t<std::is_convertible<FROM*, TO*>::value>;
在实现智能指针之前,先实现默认的删除器。需要留意的是存在有类型为数组的智能指针,因此需要实现删除器的特例:
// default deleter
template<typename T>
struct default_deleter final {
public:
constexpr default_deleter() noexcept = default;
template<typename U, typename = pointers_are_convertible<U, T>>
default_deleter(const default_deleter<U>&) noexcept {}
void operator()(T* ptr) const noexcept {
delete ptr;
}
};
template<typename T>
struct default_deleter<T[]> {
public:
constexpr default_deleter() noexcept = default;
template<typename U, typename = pointers_are_convertible<U, T>>
default_deleter(const default_deleter<U>&) noexcept {}
template<typename U, typename = pointers_are_convertible<U, T>>
default_deleter(default_deleter<U>&&) noexcept {}
virtual void operator()(T* ptr) const noexcept {
delete[] ptr;
}
};
以下是class unique_ptr
template<typename T, typename Deleter = default_deleter<T>>
class unique_ptr final {
public:
// Member types
using pointer = T*;
using element_type = T;
using deleter_type = Deleter;
private:
pointer ptr;
Deleter deleter;
public:
// Member function
constexpr unique_ptr() noexcept : ptr(nullptr) {}
constexpr unique_ptr(std::nullptr_t) noexcept : ptr(nullptr) {}
explicit unique_ptr(pointer res) : ptr(res) {}
unique_ptr(pointer res, const deleter_type& deleter) noexcept
: ptr(res), deleter(deleter) {}
unique_ptr(pointer res, deleter_type&& deleter)
: ptr(res), deleter(move(deleter)) {}
unique_ptr(const unique_ptr&) = delete;
unique_ptr(unique_ptr&& other) noexcept
: ptr(other.release()), deleter(move(other.get_deleter())) {}
template<typename Y, typename D,
typename = pointers_are_convertible<typename unique_ptr<Y, D>::element_type, T>>
unique_ptr(unique_ptr<Y, D>&& other) noexcept
: ptr(static_cast<pointer>(other.release())),
deleter(move(static_cast<deleter_type>(other.release()))) {}
~unique_ptr() {
if (ptr) {
deleter(ptr);
}
}
public:
// operator override
unique_ptr& operator=(const unique_ptr&) = delete;
unique_ptr& operator=(unique_ptr&& rhs) noexcept {
if (this == &rhs)
return *this;
reset(rhs.release());
deleter = move(rhs.get_deleter());
return *this;
}
template<typename Y, typename D,
typename = pointers_are_convertible<typename unique_ptr<Y, D>::element_type, T>>
unique_ptr & operator=(unique_ptr<Y, D>&& rhs) noexcept {
reset(static_cast<pointer>(rhs.release()));
deleter = move(static_cast<Deleter>(rhs.get_deleter()));
return *this;
}
public:
// modifiers
pointer release() noexcept {
pointer old = ptr;
ptr = nullptr;
return old;
}
void reset(pointer p = pointer{}) noexcept {
pointer old = ptr;
ptr = p;
if (old)
deleter(old);
}
void swap(unique_ptr& other) noexcept {
if (this != other) {
swap(ptr, other.ptr);
swap(deleter, other.deleter);
}
}
public:
// Observers
pointer get() const noexcept {
return ptr;
}
deleter_type& get_deleter() noexcept {
return deleter;
}
const deleter_type& get_deleter() const noexcept {
return deleter;
}
explicit operator bool() const noexcept {
return ptr;
}
T& operator*() const {
return *ptr;
}
pointer operator->() const noexcept {
return ptr;
}
};
template<typename CharT, typename Traits, typename T, typename D>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
const unique_ptr<T, D>& unique) {
std::cout << *unique;
return os;
}
template<typename T, typename ...Args,
typename = enable_if_t<!::std::is_array<T>::value>>
unique_ptr<T> make_unique(Args&& ...args) {
return unique_ptr<T>(new T(forward<Args>(args)...));
}
template<typename T,
typename = enable_if_t<is_unbounded_array<T>::value>>
unique_ptr<T> make_unique(std::size_t size) {
return unique_ptr<T>(new std::remove_extent_t<T>[size]());
}
/// ???
template<typename T, typename...Args>
enable_if_t<is_bounded_array<T>::value>
make_unique(Args&&...) = delete;
template<class T,
typename = enable_if_t<!::std::is_array<T>::value>>
unique_ptr<T> make_unique_for_overwrite() {
return unique_ptr<T>(new T);
}
template<typename T,
typename = enable_if_t<is_unbounded_array<T>::value>>
unique_ptr<T> make_unique_for_overwrite(size_t size) {
return unique_ptr<T>(new std::remove_extent_t<T>[size]);
}
/// ???
template<typename T, typename...Args>
enable_if_t<is_bounded_array<T>::value>
make_unique_for_overwrite(Args&&...) = delete;
template<typename T1, class D1, typename T2, class D2>
bool operator==(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
{
return lhs.get() == rhs.get();
}
template<typename T1, class D1, typename T2, class D2>
bool operator!=(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
{
return !(lhs == rhs);
}
template<typename T1, class D1, typename T2, class D2>
bool operator<(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
{
return lhs.get() < rhs.get();
}
template<typename T1, class D1, typename T2, class D2>
bool operator>(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
{
return rhs < lhs;
}
template<typename T1, class D1, typename T2, class D2>
bool operator<=(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
{
return !(rhs < lhs);
}
template<typename T1, class D1, typename T2, class D2>
bool operator>=(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
{
return !(lhs < rhs);
}
template<typename T, class D>
bool operator==(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
{
return !lhs;
}
template<typename T, class D>
bool operator==(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
{
return !rhs;
}
template<typename T, class D>
bool operator!=(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
{
return (bool)lhs;
}
template<typename T, class D>
bool operator!=(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
{
return (bool)rhs;
}
template<typename T, class D>
bool operator<(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
{
return lhs.get() < nullptr;
}
template<typename T, class D>
bool operator<(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
{
return nullptr < rhs.get();
}
template<typename T, class D>
bool operator>(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
{
return nullptr < lhs;
}
template<typename T, class D>
bool operator>(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
{
return rhs < nullptr;
}
template<typename T, class D>
bool operator<=(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
{
return !(nullptr < lhs);
}
template<typename T, class D>
bool operator<=(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
{
return !(rhs < nullptr);
}
template<typename T, class D>
bool operator>=(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
{
return !(lhs < nullptr);
}
template<typename T, class D>
bool operator>=(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
{
return !(nullptr < rhs);
}
template<typename T, class D>
void swap(unique_ptr<T, D>& lhs, unique_ptr<T, D>& rhs) noexcept
{
lhs.swap(rhs);
}
template<typename R, typename D, typename OtherType>
using is_constructible_from = std::enable_if<
std::is_same<OtherType*, typename unique_ptr<R, D>::pointer>::value ||
std::is_same<OtherType*, std::nullptr_t>::value ||
(std::is_same<typename unique_ptr<R, D>::pointer, typename unique_ptr<R, D>::element_type*>::value
&& std::is_convertible<OtherType(*)[], R(*)[]>::value)
>;
template<typename R1, class D1, typename R2, class D2>
using is_constructible_from_array = std::enable_if<
std::is_array<R2>::value&&
std::is_same<typename unique_ptr<R1, D1>::pointer, typename unique_ptr<R1, D1>::element_type*>::value&&
std::is_same<typename unique_ptr<R2, D2>::pointer, typename unique_ptr<R2, D2>::element_type*>::value&&
std::is_convertible<typename unique_ptr<R2, D2>::element_type(*)[], typename unique_ptr<R2, D2>::element_type(*)[]>::value
>;
template<typename T, typename Deleter>
class unique_ptr<T[], Deleter> {
public:
using pointer = T*;
using element_type = T;
using deleter_type = Deleter;
private:
pointer ptr;
deleter_type deleter;
public:
constexpr unique_ptr() noexcept
: ptr(nullptr), deleter(default_deleter<T[]>{}) {}
constexpr unique_ptr(::std::nullptr_t) noexcept
: ptr(nullptr), deleter(default_deleter<T[]>{}) {}
template<typename Y, typename = is_constructible_from<T, deleter_type, Y>>
explicit unique_ptr(Y* ptr) noexcept
: ptr(static_cast<pointer>(ptr)), deleter(default_deleter<T[]>{}) {}
template<typename Y, typename = is_constructible_from<T, deleter_type, Y>>
unique_ptr(Y* ptr, const deleter_type& deleter) noexcept
: ptr(static_cast<pointer>(ptr)), deleter(move(deleter)) {}
unique_ptr(unique_ptr&& other) noexcept
: ptr(other.release()), deleter(move(other.get_deleter())) {}
template<typename Y, typename D,
typename = is_constructible_from_array<T, Deleter, Y, D>>
unique_ptr(unique_ptr<Y, D>&& other) noexcept
: ptr(other.release()), deleter(move(other.get_deleter())) {}
~unique_ptr() {
if (this->ptr)
this->deleter(ptr);
}
public:
template<typename Y,
typename = TypeCanBeConstructedFrom<T, Deleter, Y>>
void reset(Y* ptr) noexcept
{
pointer old_ptr = this->ptr;
this->ptr = static_cast<pointer>(ptr);
if (old_ptr)
deleter(old_ptr);
}
void reset(::std::nullptr_t = nullptr) noexcept
{
pointer old_ptr = this->ptr;
this->ptr = nullptr;
if (old_ptr)
deleter(old_ptr);
}
pointer release() noexcept
{
pointer old_ptr = this->ptr;
this->ptr = nullptr;
return old_ptr;
}
template<typename Y, class D>
void swap(unique_ptr& other) noexcept
{
if (this == &other)
return;
tinySTL::swap(this->ptr, other.ptr);
tinySTL::swap(this->ptr, other.ptr);
}
pointer get() const noexcept
{
return ptr;
}
deleter_type& get_deleter() noexcept
{
return deleter;
}
const deleter_type& get_deleter() const noexcept
{
return deleter;
}
explicit operator bool() const noexcept
{
return ptr;
}
element_type& operator[](size_t index) const
{
return get()[index];
}
unique_ptr& operator=(unique_ptr&& other) noexcept {
if (this == &other)
return *this;
this->reset(other.release());
this->deleter = move(other.get_deleter());
return *this;
}
};
3. shared_ptr
链接同上
定义一个ControlBlock类,用于记录指针、拥有shared_ptr和weak_ptr的个数。同时,注意这里采用的是std::atomic_size_t,即std::atomic<std::size_t>实现原子操作,其底层实现参考:https://www.cnblogs.com/cnblogs-wangzhipeng/p/12549179.html
// 智能指针:shared_ptr
//
//
// for enable_shared_from_this https://segmentfault.com/a/1190000020861953
template<typename...>
using void_t = void;
template<typename T, typename = void>
struct can_enable_shared : std::false_type {};
template<typename T>
struct can_enable_shared<T, void_t<typename T::class_type>> : std::is_convertible<std::remove_cv_t<T>*,
typename T::class_type*> {};
template<typename T, typename Y>
void check_if_enable_shared(const shared_ptr<T>& other, Y* ptr, std::false_type) {}
template<typename T, typename Y>
void check_if_enable_shared(const shared_ptr<T>& other, Y* ptr, std::true_type) {
if (ptr) {
ptr->construct_weak_from(other, ptr);
}
}
template<typename T, typename Y>
void set_enable_shared(const shared_ptr<T>& other, Y* ptr) {
check_if_enable_shared<T, Y>(other, ptr,