在了解智能指针之前,需要先了解一下RAII
RAII 是 Resource Acquisition Is Initialization (请求到资源立即初始化)的缩写,它是一种设计思想,在C++里常常通过类进行实现,它在获取资源时把资源委托给一个对象,资源在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源,保障资源正常释放
RAII是智能指针的指导思想

上图中就展示了智能指针是如何运作的,将新申请到的空间给到智能指针之后,不再需要手动释放空间,因为cur 会在生命周期结束时自动析构,析构就销毁了
此时不管程序或者函数 是正常结束还是异常结束,都可以保障new 的资源正常释放
除了要保障析构,智能指针还需要重载运算符,模拟指针的行为
智能指针的问题是拷贝,当两个智能指针指向了同一个空间时,就会导致一个空间被析构两次
c++标准库是怎么解决这个问题的呢
c++标准库有多种智能指针,除了weak_ptr,其它的区别主要是解决拷贝的思路不同
auto_ptr : c++98时设计出来的智能指针,它的特点是拷贝时把被拷贝对象的资源的管理权转移给拷贝对象,这会导致被拷贝对象悬空,建议不要使用,它在c++17已移除
unique_ptr:c++11设计出来的,特点是不支持拷贝,只支持移动
shared_ptr:c++11设计出来的,特点是支持拷贝(底层使用引用计数实现),也支持移动
weak_ptr: c++11设计出来的,它不支持RAII,不能用它直接管理资源,是为了解决shared_ptr的循环引用问题产生的
auto_ptr


可以看到一旦ptr给到ptrcp ,就实现了资源转移,使得ptr悬空
unique_ptr
unique_ptr 不让拷贝,只能移动

shared_ptr
可以拷贝可以移动
原理是 有几个对象指向,引用计数就是几,然后让最后一个管理的对象释放资源

可以看到ptr由于资源被转移,引用计数为0
可以使用reset()手动释放智能指针
智能指针还重载了bool,用来判断智能指针是否为空,如果为空,返回false

虚拟指针特化
需要使用特化版本 接收 申请的连续的内存块
因为shared_ptr和unique_ptr 默认使用的delete析构,而不是使用delete[]析构

早期没有特化时,使用的是仿函数,也就是删除器来对指针进行释放

unique_ptr 传删除器还需要在模板参数里加上类型

循环引用问题
假设有两个节点,节点内部各自有next prev指针 指向之前或者之后的节点,这两个节点互相指向,a节点的next指针指向b节点,b节点的prev指针指向a节点
next指针和prev指针都是shared_ptr智能指针
同时a,b 两个节点都由shared_ptr智能指针管理,分别为n1,n2
此时n1、n2 两个智能指针的引用计数都为2,n1是因为b节点的prev指针,n2是因为a节点的next指针
当我们想要释放 a节点,需要将n1 进行reset(进行计数减减),此时计数为1,还有b节点的 prev指针指向它,此时就可以有两种做法
1、可以将b节点的prev指针进行 reset或者指向其它节点,但是这需要程序员手动进行管理,一旦程序员忘记手动释放或者指向其它节点,就会发生资源泄漏
2、让prev指针进行析构,将b节点进行释放,b节点的成员prev指针自然就进行析构了,但是这又会出现问题,因为b节点无法释放,a节点的next指针指向它,这就形成了循环引用
为了更好的解决a节点释放的问题,就引入了weak_ptr 智能指针,由于weak_ptr 不会增加引用计数,next和prev指针使用weak_ptr进行管理,a节点就不会因为b节点释放不了

可以使用shared_ptr进行构造,内部只是接收了指针,没有接收引用计数


weak_ptr 内部支持expired检查指向的资源有没有过期(没过期就会返回0,过期就会返回1),同时还提供了use_count接口 来获取指向的shared_ptr的引用计数,还可以调用lock 来返回一个shared_ptr对象用来管理自己指向的资源(weak_ptr 是没法访问指向资源的),如果指向资源已经过期,就会返回一个空的shared_ptr对象