unique_ptr
对象之间不允许进行拷贝,即一个unique_ptr
对象管理一块堆区内存资源,是一一对应的关系unique_ptr
的简单实现原理: //不允许拷贝的智能指针
//delfunc是堆区资源释放函数,用于调用delete或者delete[]
template<class T,class delfunc>
class unique_ptr
{
public:
unique_ptr(T * ptr = nullptr)
:_ptr(ptr)
{}
~unique_ptr()
{
if (_ptr)
{
delfunc del;
del(_ptr);
std::cout << "delete" << std::endl;
}
}
//让智能指针可以像指针一样被使用
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
//禁止unique_ptr对象间的拷贝
unique_ptr(const unique_ptr<T, delfunc>& unptr) = delete;
unique_ptr<T, delfunc>& operator=(const unique_ptr<T, delfunc>& unptr) = delete;
private:
T* _ptr;
};
delete
完成资源释放,而对象数组要采用delete[]
完成资源释放.unique_ptr
的类模板参数delfunc
的设计目的就是为了区分上述两种情况,让使用者通过设计仿函数的方式在delete
和delete[]
之间做选择shared_ptr
是允许进行拷贝的智能指针,然而shared_ptr
对象之间发生拷贝时,就会出现多个智能指针对象同时管理同一块堆区内存的情况,shared_ptr
通过引用计数的技术避免了同一块堆区资源被释放多次的情况出现:shared_ptr
的简单实现原理: //允许拷贝的智能指针,利用引用计数解决内存管理冲突
//delfunc是堆区资源释放函数,用于调用delete或者delete[]
template<class T, class delfunc>
class shared_ptr
{
public:
//构造智能指针(同时创建引用计数变量)
shared_ptr(T* ptr = nullptr)
:_ptr(ptr),
_recount(new int(1))
{}
shared_ptr(const shared_ptr<T, delfunc>& shptr)
: _ptr(shptr._ptr),
_recount(shptr._recount)
{
//智能指针拷贝增加引用计数
(*_recount)++;
}
shared_ptr<T, delfunc>& operator=(const shared_ptr<T, delfunc>& shptr)
{
if (_ptr != shptr._ptr)
{
//智能指针指向改变,其先前指向的堆区内存和引用计数变量需要处理
Release();
//完成智能指针拷贝并增加引用计数
_ptr = shptr._ptr;
_recount = shptr._recount;
++(*_recount);
}
return (*this);
}
~shared_ptr()
{
Release();
}
//让智能指针可以像指针一样被使用
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T* getptr() const
{
return _ptr;
}
private:
//将资源释放函数进行封装,方便复用
//引用计数减一,若引用计数减为0则释放资源
void Release()
{
//引用计数减一
--(*_recount);
//引用计数为0则释放资源
if (*_recount == 0)
{
if (_ptr)
{
delfunc del;
del(_ptr);
std::cout << "delete" << std::endl;
}
//同时注意释放引用计数变量
delete _recount;
}
}
private:
T* _ptr;
int* _recount;
};
shared_ptr
类内部同时还要解决引用计数变量带来的线程安全的问题,这里暂不讨论shared_ptr
用在自引用结构体中会出现对象无法析构的问题:
template<class T>
class deletefunc
{
public:
void operator()(T* ptr)
{
delete ptr;
}
};
// 循环引用
struct ListNode
{
int _val;
shared_ptr<ListNode,deletefunc<ListNode>> _next;
shared_ptr<ListNode,deletefunc<ListNode>> _prev;
~ListNode()
{
cout << "~ListNode()" << endl;
}
};
// 循环引用
void test_shared_cycle()
{
share_ptr<ListNode, deletefunc<ListNode>> n1(new ListNode);
share_ptr<ListNode, deletefunc<ListNode>> n2(new ListNode);
n1->_next = n2;
n2->_prev = n1;
}
test_shared_cycle()
函数执行完后,两个链表节点都无法正常析构,shared_ptr
引发了循环引用的问题:n1
节点的析构依赖于n2
节点中_prev
指针的析构,n2
节点中_prev
指针的析构依赖于n2
节点的析构,n2
节点的析构又依赖于n1
节点中_next
指针的析构, n1
节点中_next
指针的析构又依赖于n1
节点的析构.如此往复构成了循环的依赖关系导致两个节点都无法被释放.weak_ptr
就是为了解决循环引用问题而设计的weak_ptr
智能指针不参与堆区内存的申请和释放,也不会增加特定内存块的引用计数(其功能和普通指针差不多),weak_ptr
支持以shared_ptr
为引用形参的拷贝构造和赋值weak_ptr
简单实现原理: //用于配合share_ptr的使用用于循环引用的场景
//delfunc是堆区资源释放函数,用于调用delete或者delete[]
//weak_ptr不参与资源的申请和释放
template<class T, class delfunc>
class weak_ptr
{
public:
weak_ptr()
:_ptr(nullptr)
{}
~weak_ptr()
{}
weak_ptr(const weak_ptr<T, delfunc>& wptr)
:_ptr(wptr._ptr)
{}
weak_ptr(const share_ptr<T, delfunc>& shptr)
:_ptr(shptr.getptr())
{}
weak_ptr<T, delfunc>& operator=(const weak_ptr<T, delfunc>& wptr)
{
_ptr = wptr._ptr;
return (*this);
}
weak_ptr<T, delfunc>& operator=(const share_ptr<T, delfunc>& shptr)
{
_ptr = shptr.getptr();
return (*this);
}
//让智能指针可以像指针一样被使用
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};