可以通过模板参数指定Lock_Policy

  1. class sp_counted_Base{}

    • use_count => 当减为0析构资源 dispose
    • weak_count => 当减为0 delete this; destroy释放控制区域

      二者皆为原子变量,原子操作改变值,同时使用内存屏障确保可见性 dispose一定要能被调用destroy的线程观察到

  2. class sp_counted_Ptr{} 继承了 sp_counted_Base
  3. class sp_counted_deleter{} 继承了sp_counted_Base,存储了Deleter_,使用std::addressof 1获取地址

    非常有趣,当面对模板时,传入的类型的& operator可能被重载,并非取地址的含义,因此使用这个弥补。

  4. class _shared_count进一步封装,作为控制块
  5. class _shared_ptr继承了class shared_ptr_access,后者重载了* 和 -> 运算符
  6. class _weak_ptr使用class _weak_count作为控制块,增加引用计数有区别
  7. class enable_shared_from_this使用 weak_ptr weak_this来实现自身返回shared_ptr

    实现原理并没有什么黑魔法:当从指针构造shared_ptr时,在weak_this中进行记录(将this指针赋值给weak_this),当使用shared_from_this的时候,将weak_this提升为shared_ptr返回

  8. Atomic 的实现采用了 int + atomic_fetch_and_add + atomic_thread_fence(memory barrier)因为是非原子操作,所以才需要内存屏障

注释1:

  1. 如果开启EBO(类型满足不为final且为空),则Sp_ebo_helper继承了_Tp, 直接将该对象转为_Tp类型对象
  2. 如果不开启,有一个成员变量存储_Tp对象
  3. 而_Impl又继承了 Sp_ebp_helper, 相当于直接继承了这个对象?
  4. __Sp_counted_ptr 是默认删除器,使用delete删除
  5. 当传入自定义删除器时,构造一个Sp_counted_deleter
  6. 在探究为什么get_deleter函数需要rtti信息时,有了意外收获,虚函数的正确调用不需要rtti2

    为什么? 因为需要主动校对type_info信息

  7. 在shared_ptr构造的时候,需要检验是否有weak_this.这一处是模板精髓(检测对象是否拥有某个成员函数)
classDiagram
    class __shared_ptr
    __shared_ptr <|-- shared_ptr
    __shared_ptr: + element_type* _M_ptr
    __shared_ptr: + __shared_count _M_refcount
    
    __shared_count *-- __shared_ptr
    
        __weak_ptr <|-- weak_ptr
    __weak_count *-- __weak_ptr
    __shared_counted_base *-- __weak_count
    
    
    __shared_counted_base *-- __shared_count
    class __shared_counted_base
    __shared_counted_base: + _Atomic_word  _M_use_count
    __shared_counted_base: + _Atomic_word  _M_weak_count
    
    __shared_counted_base <|-- __Sp_counted_deleter
    __Impl *-- __Sp_counted_deleter
    __Sp_ebo_helper <|-- __Impl
    
    class __Sp_counted_ptr

扩展:dynamic_cast原理和rtti

开启 fno-rtti 后,不可以使用dynamic_cast 和 typeid,但是节省空间

dynamic_cast 和 typeid 都使用了额外的空间来存储必要的类型信息(type_info),运行时查找这些信息去判断。而虚函数的调用不需要这些信息。

扩展:为什么unique_ptr大小和指针相同

使用了(employ) EBO (empty base optimization),作为基类初始化不需要占用额外空间,详见3

当使用了empty deleter object (重载了()的类)且unique_ptr使用了EBO后

扩展:其他笔记4


  1. why use std::addressof versus &: https://stackoverflow.com/que...
  2. shared_ptr withou rtti: https://stackoverflow.com/que...
  3. overhead of custom deleter: https://www.bourez.be/?p=19
  4. 一位博主的智能指针源码阅读 https://blog.csdn.net/kupepoe...

七月流火
1 声望1 粉丝