跳转至

智能指针

智能指针定义在头文件<memory>中。

1 shared_ptr

  • 实现原理分析:
  • shared_ptr 内部保存一个对象指针和一个引用计数类 _Ref_count 指针,通过 _Ref_count 继承自 _Ref_count_base 中引用计数变量来判断是否需要对保存的指针进行 delete,当引用 计数变量==0 时,_Ref_count 会对保存的对象,以及 _Ref_count 自身资源进行释放
  • 引用计数类主要2个功能:管理内存、引用计数
  • 所有对shared_ptr对象的拷贝赋值,都会触发引用计数+1。
  • shares_Ptr对象的析构会触发引用计数-1。

1.1 类shared_ptr分析

shared_ptr公有继承自_Ptr_base,在shared_ptr类中主要实现构造,赋值等操作,实际引用计数,对象指针数据都在_Ptr_base中实现 - shared_ptr部分源码

class shared_ptr : public _Ptr_base<_Ty> { // class for reference counted resource management
private:
    using _Mybase = _Ptr_base<_Ty>;

public:
    using typename _Mybase::element_type;
//其中一个构造函数    
    template <class _Ux,
    enable_if_t<conjunction_v<conditional_t<is_array_v<_Ty>, _Can_array_delete<_Ux>, _Can_scalar_delete<_Ux>>,
    _SP_convertible<_Ux, _Ty>>,
    int> = 0>
    explicit shared_ptr(_Ux* _Px) { // construct shared_ptr object that owns _Px
#if _HAS_IF_CONSTEXPR
        if constexpr (is_array_v<_Ty>) {
            _Setpd(_Px, default_delete<_Ux[]>{});
        } else {
          //_Owner临时保存_Px指针
            _Temporary_owner<_Ux> _Owner(_Px);
            //_Set_ptr_rep_and_enable_shared函数用来给_Ptr_base中的_Ptr和_Rep赋值,Ref_count中也保存_Px指针
            _Set_ptr_rep_and_enable_shared(_Owner._Ptr, new _Ref_count<_Ux>(_Owner._Ptr));
            _Owner._Ptr = nullptr;
        }
    //声明使用_Ptr_base中保护函数get,并将它转出公有函数get
    using _Mybase::get;
    //析构会调用引用计数-1,当引用计数==0时,会释放资源
    ~shared_ptr() noexcept { // release resource
      this->_Decref();
    }
}

1.2 类_Ptr_base分析

_Ptr_base中有2个重要的指针成员变量,一个是保存的数据对象的指针,另一个控制类型指针_Ref_count_base,用来实现引用计数及删除保存对象指针所占内存功能 - _Ptr_base部分源码

template <class _Ty>
class _Ptr_base { // base class for shared_ptr and weak_ptr
public:
//如果是数组型,将会移除[]
    using element_type = remove_extent_t<_Ty>;
//获取引用计数数
    _NODISCARD long use_count() const noexcept {
        return _Rep ? _Rep->_Use_count() : 0;
    }

protected:
//返回保存的对象的指针
    _NODISCARD element_type* get() const noexcept {
        return _Ptr;
    }

    constexpr _Ptr_base() noexcept = default;

    ~_Ptr_base() = default;
//移动构造会用到的函数,只交换数据,引用计数并不会增加或减少,_Other不再使用
    template <class _Ty2>
    void _Move_construct_from(_Ptr_base<_Ty2>&& _Right) noexcept {
        // implement shared_ptr's (converting) move ctor and weak_ptr's move ctor
        _Ptr = _Right._Ptr;
        _Rep = _Right._Rep;

        _Right._Ptr = nullptr;
        _Right._Rep = nullptr;
    }
//拷贝构造会使用的函数,引用计数+1
    template <class _Ty2>
    void _Copy_construct_from(const shared_ptr<_Ty2>& _Other) noexcept {
        // implement shared_ptr's (converting) copy ctor
        _Other._Incref();

        _Ptr = _Other._Ptr;
        _Rep = _Other._Rep;
    }
//使用新对象指针替换原指针,引用计数+1
    template <class _Ty2>
    void _Alias_construct_from(const shared_ptr<_Ty2>& _Other, element_type* _Px) noexcept {
        // implement shared_ptr's aliasing ctor
        _Other._Incref();

        _Ptr = _Px;
        _Rep = _Other._Rep;
    }
//使用新对象指针替换原指针,移动构造引用计数不变,_Other不再使用
    template <class _Ty2>
    void _Alias_move_construct_from(shared_ptr<_Ty2>&& _Other, element_type* _Px) noexcept {
        // implement shared_ptr's aliasing move ctor
        _Ptr = _Px;
        _Rep = _Other._Rep;

        _Other._Ptr = nullptr;
        _Other._Rep = nullptr;
    }

    template <class _Ty0>
    friend class weak_ptr; // specifically, weak_ptr::lock()

    template <class _Ty2>
    bool _Construct_from_weak(const weak_ptr<_Ty2>& _Other) noexcept {
        // implement shared_ptr's ctor from weak_ptr, and weak_ptr::lock()
        if (_Other._Rep && _Other._Rep->_Incref_nz()) {
            _Ptr = _Other._Ptr;
            _Rep = _Other._Rep;
            return true;
        }

        return false;
    }
//引用计数+1
    void _Incref() const noexcept {
        if (_Rep) {
            _Rep->_Incref();
        }
    }
//引用计数-1
    void _Decref() noexcept { // decrement reference count
        if (_Rep) {
            _Rep->_Decref();
        }
    }

private:
//保存对象的指针
    element_type* _Ptr{nullptr};
//用来控制引用计数及删除对象功能
    _Ref_count_base* _Rep{nullptr};



#if _HAS_STATIC_RTTI
//用来获取删除器函数指针
    template <class _Dx, class _Ty0>
    friend _Dx* get_deleter(const shared_ptr<_Ty0>& _Sx) noexcept;
#endif // _HAS_STATIC_RTTI
};

1.3 类_Ref_count_base分析

引用计数类_Ref_count_base是一个抽象类,定义了一些基础方法,主要处理引用计数+-,以及何时delete保存的指针。它有一个子类_Ref_count,在智能指针中使用的是这个子类_Ref_count - _Ref_count_base部分源码

// CLASS _Ref_count_base
class __declspec(novtable) _Ref_count_base { // common code for reference counting
private:
#ifdef _M_CEE_PURE
    // permanent workaround to avoid mentioning _purecall in msvcurt.lib, ptrustu.lib, or other support libs
    virtual void _Destroy() noexcept {
        _STD terminate();
    }

    virtual void _Delete_this() noexcept {
        _STD terminate();
    }
#else // ^^^ _M_CEE_PURE / !_M_CEE_PURE vvv
    virtual void _Destroy() noexcept     = 0; // destroy managed resource
    virtual void _Delete_this() noexcept = 0; // destroy self
#endif // _M_CEE_PURE
// 初始化引用计数值为1,这个值控制引用计数
    _Atomic_counter_t _Uses  = 1;
    _Atomic_counter_t _Weaks = 1;

public:
// 引用计数+1,_MT_INCR(_Uses)是微软实现的具有原子操作的+1
    void _Incref() noexcept { // increment use count
        _MT_INCR(_Uses);
    }

    void _Incwref() noexcept { // increment weak reference count
        _MT_INCR(_Weaks);
    }
// 引用计数-1 当引用计数==0时会执行一系列delete操作,删除保存的指针对象以及自身
    void _Decref() noexcept { // decrement use count
        if (_MT_DECR(_Uses) == 0) {
            _Destroy();
            _Decwref();
        }
    }

    void _Decwref() noexcept { // decrement weak reference count
        if (_MT_DECR(_Weaks) == 0) {
            _Delete_this();
        }
    }
//返回引用计数值
    long _Use_count() const noexcept {
        return static_cast<long>(_Uses);
    }

};

1.4 类_Ref_count分析

_Ref_count_Ref_count_base的子类,它的作用是实现资源释放的具体操作。 - _Ref_count部分源码

// CLASS TEMPLATE _Ref_count
template <class _Ty>
class _Ref_count : public _Ref_count_base { // handle reference counting for pointer without deleter
public:
//用待保存的对象构造实例对象
    explicit _Ref_count(_Ty* _Px) : _Ref_count_base(), _Ptr(_Px) {}

private:
//删除保存的对象
    virtual void _Destroy() noexcept override { // destroy managed resource
        delete _Ptr;
    }
//删除自身
    virtual void _Delete_this() noexcept override { // destroy self
        delete this;
    }
//智能指针保存的对象指针,与_Ptr_base中的对象指针是同一个
    _Ty* _Ptr;
};

2 weak_ptr

  • 特点:
  • 它只能接受weak_ptrshared_ptr,使用时需要先转成shared_ptr再通过shared_ptr去访问保存的指针对象
  • 它是一种弱引用,没有引用计数,不负责管理内存,它的存在与否不影响原指针对象的释放

2.1 类weak_ptr分析

weak_ptr中有3个重要的函数,用来管理weak_ptr,其中lock函数用来获取shared_ptr - weak_ptr部分源码及分析

// CLASS TEMPLATE weak_ptr
template <class _Ty>
class weak_ptr : public _Ptr_base<_Ty> { // class for pointer to reference counted resource
public:
//这个会释放引用的shared_ptr
    void reset() noexcept { // release resource, convert to null weak_ptr object
        weak_ptr{}.swap(*this);
    }

    void swap(weak_ptr& _Other) noexcept {
        this->_Swap(_Other);
    }
//用来判断被管理对象是否被删除
    _NODISCARD bool expired() const noexcept {
        return this->use_count() == 0;
    }
//用来获取引用的shared_ptr
    _NODISCARD shared_ptr<_Ty> lock() const noexcept { // convert to shared_ptr
        shared_ptr<_Ty> _Ret;
        //通过weak_ptr获得shared_ptr,如果成功则返回引用的shared_ptr,否则得到的是空shared_ptr
        (void) _Ret._Construct_from_weak(*this);
        return _Ret;
    }
};

2.2 类_Ptr_base分析

_Ptr_base_Construct_from_weak_Construct_from_weak这2个函数很重要,实现了shared_ptrweak_ptr的转换 - _Ptr_base部分源码

template <class _Ty>
class _Ptr_base { // base class for shared_ptr and weak_ptr
public:
    using element_type = remove_extent_t<_Ty>;

protected:
    _NODISCARD element_type* get() const noexcept {
        return _Ptr;
    }

    constexpr _Ptr_base() noexcept = default;

    ~_Ptr_base() = default;

    template <class _Ty0>
    friend class weak_ptr; // specifically, weak_ptr::lock()

    template <class _Ty2>
    bool _Construct_from_weak(const weak_ptr<_Ty2>& _Other) noexcept {
        // implement shared_ptr's ctor from weak_ptr, and weak_ptr::lock()
        if (_Other._Rep && _Other._Rep->_Incref_nz()) {
            _Ptr = _Other._Ptr;
            _Rep = _Other._Rep;
            return true;
        }

        return false;
    }
//shared_ptr转weak_ptr,如果引用计数控制指针_Rep不为空,则表示shared_ptr保存着有效指针对象,指针对象和引用计数指针赋值,弱引用计数+1
    template <class _Ty2>
    void _Weakly_construct_from(const _Ptr_base<_Ty2>& _Other) noexcept { // implement weak_ptr's ctors
        if (_Other._Rep) {
            _Ptr = _Other._Ptr;
            _Rep = _Other._Rep;
            _Rep->_Incwref();
        } else {
            _STL_INTERNAL_CHECK(!_Ptr && !_Rep);
        }
    }
//弱引用计数+1
    void _Incwref() const noexcept {
        if (_Rep) {
            _Rep->_Incwref();
        }
    }
//弱引用计数-1
    void _Decwref() noexcept { // decrement weak reference count
        if (_Rep) {
            _Rep->_Decwref();
        }
    }

private:
    element_type* _Ptr{nullptr};
    _Ref_count_base* _Rep{nullptr};

};

3 unique_ptr

  • unique_ptr独占指针,与shared_ptr共享特性相反。
  • uniqe_ptr不能拷贝构造拷贝赋值,但支持移动构造和移动赋值。
title: uniqe_ptr怎么实现不能构造的?
`uniqe_ptr`类中将拷贝构造和移动赋值设置成delete状态,使赋值失效
```cpp
    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;
title: 怎么将一个uniqe_ptr赋给另一个uniqe_ptr?
因为`uniqe_ptr`支持移动语义,因此我们使用`move`来转移对象
```cpp
    unique_ptr<A> uA1(new A);
    //unique_ptr<A> uA2 = uA1; error 
    unique_ptr<A> uA2 = move(uA1);
    //unique_ptr<A> uA3(uA2);error 
    unique_ptr<A> uA3(move(uA2));