手动实现C++11的智能指针
unique_ptr
功能
unique_ptr独占资源,并使用RAII的方式管理资源。
设计思想
1)仅仅利用RAII的思想取管理资源,即类初始化时,获取资源;类析构时,释放资源;
2)并且为了保证资源独占性,禁用了拷贝函数;
源码
unique_ptr.h
#pragma once
template<typename T>
class unique_ptr {
public:
unique_ptr()noexcept{}
unique_ptr(T* Ptr) :_Ptr(Ptr) {}
unique_ptr(unique_ptr&& right)noexcept {
swap(right._Ptr, _Ptr);
}
unique_ptr& operator=(unique_ptr&& right) {
if (this == &right) return *this;
deconstruct();
_Ptr = right._Ptr;
right._Ptr = nullptr;
return *this;
}
~unique_ptr() {
deconstruct();
}
T& operator*() {
return *_Ptr;
}
T* operator->() {
return _Ptr;
}
T* get() {
return _Ptr;
}
T* release() {
T* old = nullptr;
swap(_Ptr, old);
return old;
}
void reset(T* Ptr = nullptr) {
deconstruct();
_Ptr = Ptr;
}
private:
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
void deconstruct() {
if (_Ptr != nullptr) {
delete _Ptr;
_Ptr = nullptr;
}
}
T* _Ptr{nullptr};
};
shared_ptr与weak_ptr
功能
1)shared_ptr共享指针,允许多个shared_ptr实例管理同一份资源;
2)weak_ptr持有资源,但不管理资源;
设计思想
1)一份资源Ptr对应一份引用计数器Ref_Count;即管理同一个资源Ptr的shared_ptr实例和weak_ptr实例,都具有同一份共享的引用计数器Ref_Count;
2)shared_ptr利用引用计数器的思想管理资源。当Ref_Count的共享计数Use减为0时,释放资源Ptr;当Ref_Count的weak弱引用计数减为0时,释放该共享的引用计数器;
3)weak_ptr可以根据Ref_Count是否为nullptr以及Ref_Count中的贡献计数Use是否为0,来判断当前是否存在可用资源Ptr;
3)在C++中的shared_ptr实际上支持传入std::make_shared,可以将资源Ptr的内存空间和引用计数器Ref_Count的内存空间一起申请,优点有两点:1. 避免异常安全问题,如new资源后,再new引用计数器Ref_Count失败的话,可能会导致资源泄漏;2. 原来的两次资源分配只需要一次,且地址可以连续(有利于缓存?);但也有一个缺点,即内存空间的延迟释放,需要等Ref_Count的计数都为0时,才会释放这块空间;
源码
ref_count.h
#pragma once
class Ref_Count {
private:
int uses = 1;
int weak = 1;
protected:
virtual void destory_this() = 0;
virtual void destory_resource() = 0;
public:
Ref_Count() {
}
virtual ~Ref_Count() noexcept {}
void incref() {
++uses;
}
void incwref() {
++weak;
}
void decref() {
--uses;
if (uses == 0) {
destory_resource();
decwref();
}
}
void decwref() {
--weak;
if (weak == 0) {
destory_this();
}
}
int use_count() {
return uses;
}
};
template<typename T>
class Ref_count_resource :public Ref_Count {
private:
T* res;
void destory_this() {
delete this;
}
void destory_resource() {
delete res;
}
public:
Ref_count_resource(T* res_) :res(res_) {}
Ref_count_resource(const T* res_) :res(res_) {}
};
weak_ptr.h
#pragma once
#include"ref_count.h"
#include"shared_ptr.h"
template<typename T>
class weak_ptr {
public:
weak_ptr(){}
weak_ptr(const shared_ptr<T>& sp):_Ptr(sp._Ptr),_Ref_count(sp._Ref_count) {
if (_Ref_count) _Ref_count->incwref();
}
weak_ptr(const weak_ptr& other):_Ptr(other._Ptr), _Ref_count(other._Ref_count) {
if (_Ref_count) _Ref_count->incwref();
}
weak_ptr(weak_ptr&& right){
swap(_Ptr, right._Ptr);
swap(_Ref_count, right._Ref_count);
}
~weak_ptr() {
if (_Ref_count) _Ref_count->decwref();
}
weak_ptr& operator=(const weak_ptr& other) {
if (&other == this) return *this;
if (_Ref_count) _Ref_count->decwref();
_Ptr = other._Ptr;
_Ref_count = other._Ref_count;
if (_Ref_count) _Ref_count->incwref();
}
weak_ptr& operator=(weak_ptr&& right) {
if (&right == this) return *this;
if (_Ref_count) _Ref_count->decref();
_Ref_count = nullptr;
_Ptr = nullptr;
swap(_Ref_count, right._Ref_count);
swap(_Ptr, right._Ptr);
}
weak_ptr& operator=(const shared_ptr<T>& sp) {
if (_Ref_count) _Ref_count->decwref();
_Ptr = sp._Ptr;
_Ref_count = sp._Ref_count;
if (_Ref_count) _Ref_count->incwref();
return *this;
}
shared_ptr<T> lock() {
if (expire()) return shared_ptr<T>();
return shared_ptr<T>(_Ptr, _Ref_count);
}
bool expire() {
return !_Ref_count || _Ref_count->use_count() == 0;
}
int use_count() {
if (_Ref_count) return _Ref_count->use_count();
return 0;
}
private:
T* _Ptr{ nullptr };
Ref_Count* _Ref_count{ nullptr };
};
shared_ptr.h
#pragma once
#include"ref_count.h"
template <typename T>
class weak_ptr;
template<typename T>
class shared_ptr {
private:
shared_ptr(T* Ptr, Ref_Count* Ref_count):_Ptr(Ptr),_Ref_count(Ref_count) {
if(_Ref_count)
_Ref_count->incref();
}
public:
shared_ptr()noexcept{}
shared_ptr(T* Ptr) :_Ptr(Ptr), _Ref_count(new Ref_count_resource<T>(Ptr)) {}
shared_ptr(const shared_ptr& other) :_Ptr(other._Ptr), _Ref_count(other._Ref_count) {
if(_Ref_count)
_Ref_count->incref();
}
shared_ptr(shared_ptr&& right){
swap(_Ptr, right._Ptr);
swap(_Ref_count, right._Ref_count);
}
~shared_ptr() {
if(_Ref_count)
_Ref_count->decref();
}
shared_ptr& operator=(const shared_ptr& other) {
if (&other ==this) return *this;
if (_Ref_count) _Ref_count->decref();
_Ref_count = other._Ref_count;
_Ptr = other._Ptr;
if(_Ref_count) _Ref_count->incref();
return *this;
}
shared_ptr& operator=(shared_ptr&& right) {
if (&right == this) return *this;
if(_Ref_count) _Ref_count->decref();
_Ref_count = nullptr;
_Ptr = nullptr;
swap(_Ref_count, right._Ref_count);
swap(_Ptr, right._Ptr);
}
int use_count() {
if (_Ref_count) return _Ref_count->use_count();
return 0;
}
bool unique() {
return !_Ref_count || _Ref_count->use_count() == 1;
}
T& operator*() {
return *_Ptr;
}
T* operator->() {
return _Ptr;
}
T* get() {
return _Ptr;
}
private:
T* _Ptr{nullptr};
Ref_Count* _Ref_count{nullptr};
friend weak_ptr<T>;
};