shared_ptr

shared_ptr继承自_Ptr_base<_Ty>,是一个引用计数资源管理的类。

_Ptr_base是shared_ptr和weak_ptr的基类。

Ptr_base

image

Ptr_base持有两个数据成员,element_type和_Ref_count_base
对相同模板参数的shared_ptr可以访问,对一系列模板家族的_Ptr_base可以访问,对一系列模板参数的atomic可以访问。

element_type

image
element_type萃取了_Ty的类型,如果_Ty是数组,则萃取出元素的类型。

_Ref_count_base

通用的代码用于引用计数。

_Ref_count_base有两个虚函数,_Destroy和_Delete_this函数,第一个是销毁管理的资源,第二个是销毁自己。

image
还有两个原子类型,一个是_Uses,一个是_Weaks。

    bool _Incref_nz() noexcept { // increment use count if not zero, return true if successful
        auto& _Volatile_uses = reinterpret_cast<volatile long&>(_Uses);
#ifdef _M_CEE_PURE
        long _Count = *_Atomic_address_as<const long>(&_Volatile_uses);
#else
        long _Count = __iso_volatile_load32(reinterpret_cast<volatile int*>(&_Volatile_uses));
#endif
        while (_Count != 0) {
            const long _Old_value = _INTRIN_RELAXED(_InterlockedCompareExchange)(&_Volatile_uses, _Count + 1, _Count);
            if (_Old_value == _Count) {
                return true;
            }

            _Count = _Old_value;
        }

        return false;
    }

看一下_Incref_nz,这个函数叫做Inc(Increment) ref(reference),nz(not zero)。
增加引用计数,如果非零的话。

_InterlockedCompareExchange,会将第一个参数的值和第三个进行比较,如果相等,则用第二个参数与第一个参数交换,并返回旧值。

还有两个函数,_Incref和_Incwref,增加use count和weak reference count,_Incref和_Incref_nz,相比,是不需要考虑非零的。

然后是_Decref和_Decwref,一个是decrement use count,另一个是decrement weak reference count。
image
_Decref的use_count减少为0后,就会销毁资源,然后调用_Decwref,减少weak引用计数,而_Decwref只会减少weak reference count,当为0的时候,就会_Delete_this。

image
这里还有个返回use count,以及返回删除器的函数。

注意,_Ref_count_base* _Rep是一个指针,这样,当两个智能指针指向同一个对象的时候,该引用计数为2,会被两个对象共享。

shared_ptr提供了一个构造函数可以自定义一个删除器去指定析构函数的删除方式。
因为用智能指向文件句柄的时候,需要调用close,而默认删除器的方式是delete ptr,还有指向数组的指针,也需要删除器。

template<class U, class D> shared_ptr(U* p, D del);//使用这种方式

weak_ptr可以获取shared_ptr指向的对象,而不会增加引用计数。

注意,weak_ptr的expired用了判断weak_ptr是否过期,而lock,则返回一个和当前weak_ptr指针指向相同的shared_ptr指针,如果过期,则返回空的shared_ptr。

双向链表内部的两个指针,一般使用weak_ptr代替。

参考文章