1.继承自Ptr_base¶
干嘛的?
ptr_base两个成员:¶
- Ptr:指向实际管理的对象
- Rep:指向控制块(包含引用计数、分配器等元数据)。 还有些友元类,可以供自己同类型的对象,子shared_Ptr对象,原子结构....直接调用私有变量。
删除拷贝构造与赋值构造¶
对象的删除(纯虚函数)¶
意识就是说智能指针的删除还得让子类自己来实现
use_count引用计数¶
这个_Rep究竟怎么计数的?
先找到这个类型:法线里面有两个原子类型的计数器。也就是说自带一个强引用和弱引用
-
_Uses
= 1
- _Weaks
= 1
_Incref_nz()
:非零时安全递增引用计数(原子读取,CAS)_Incref()
:增加强引用计数Incwref()
:增加弱引用计数_Decref
:减少强引用计数,强引用为0,还要减少弱引用,还要destroy_Decwref
:减少弱引用,弱引用为0,deletethis删除控制块自身use_count
:一个静态转换。_Get_deleter
:或得删除器的一个虚函数
2.Shared_Ptr部分¶
基类取别名¶
构造¶
- 使用默认构造
- 然后是一系列带参数的构造
- 空指针
- 裸指针:
- 数组类型:加个数组删除器
- 非数组:用新的类型管理指针,创建引用块控制块
- 带删除器的构造:删除器需可移动构造
- 带删除器和分配器的构造:分配器用于分配控制块资源
- 别名构造函数:与别名共享控制块,但指向不同变量
- 作用:如指向派生类的基类成员,但不影响原始引用计数
- 别名移动构造函数:
- 拷贝构造函数: 增加引用计数,共享同一控制块
- 移动构造函数:转移资源所有权,原shared_ptr变为空
- 从weak_ptr构造:
- 先判断weak_ptr是否过期,构造一个共享资源的share_ptr
- 过期了则抛出bad_weak_ptr
- auto_ptr构造:
- 直接获取、转换、释放
- 注意auto_ptr已经被弃用了,这个构造函数仅为兼容性保留
- 从uniqur_ptr进行构造:
- 先获取unique_ptr的指针
- 再获取unique_ptr的删除器
- 要确保删除器类型兼容shared_ptr
- 将unique_ptr转换过来
- 释放unqire_ptr的指针
- 析构函数
- 调用的是基类的减少引用Decref的方法。
- 减少引用,计数归零则释放资源
内部方法¶
swap():¶
智能指针先禁用了标准库std特化的swap,使用的是concepts库range的swap - ADL检查概念:先判断对象是类或枚举,避免对基本类型触发ADL --> - 定制点对象: - 使用ADL找到的Swap,即用户为自定义类定义了swap - 通用移动交换:经典三次移动交换 - 移动构造临时对象tmp - 移动赋值x = y - 移动赋值y = tmp - 数组交换 -
reset¶
- unique():如果use_count = 1就返回
友元方法¶
- make_shared
- allocate_shared
指针转换¶
这些本质上都是cast<_Ty*>
的处理,然后再重新进行一次构造
- static_pointer_cast:支持静态类型转换(如基类和派生类)
- const_pointer_cast:移除或添加const限定符
- reinterpret_pointer_cast:强制转换,二进制层面的指针转换(如void*)
仅在RTTI启用时有用
- dynamic_pointer_cast:支持运行时类型检查
- cast<_Ty*>
的处理
- 转换成功返回shared_Ptr,失败则返回nullptr
重载运算符¶
get
- *
- ()
- []
赋值¶
- 拷贝赋值:纯粹的swap
- 模板化拷贝赋值(支持类型转换):与普通拷贝赋值相同,但支持非法类型转换
- 能使Ty2 可安全转换为 Ty(例如派生类到基类)
- enable_if:限制模版实例化,避免非法类型转换
- 移动赋值:转移资源所有权,原指针变为空
- move将左值转换为右值引用对象后,调用移动构造,构造临时右值引用对象,(将right的资源转移过来,原right置空)
- 交换,原资源由临时对象析构时释放
- 模板化移动赋值
- auto_ptr的赋值:
- 移动语义,构造一遍
- 交换
- unique_ptr的赋值
- 捕获删除器,并将其存储到控制块中
- 移动
- 交换