C++通用智能指针的实现

shared_ptr

以下代码来至llvm-project/libcxx/include/memory,文中只截取了部分代码。

  • shared_ptr通过__shared_weak_count指针来管理引用计数。__shared_weak_count是__shared_count(实现共享指针的计数)的子类,在__shared_count的基础上实现了弱引用计数。__shared_ptr_pointer是__shared_weak_count的子类,在__shared_weak_count的基础上实现了对指针对象的管理(构造,析构),并实现父类__shared_weak_count的方法__on_zero_shared_weak(用于删除管理的指针对象)
  • 和我最开始想象中的实现有点不一样的地方是首次构造__shared_weak_count时,共享计数是0,当共享计数是-1时析构管理的指针对象,获取计数个数的时候都要在原来的基础上+1。但是为啥一个空的shared_ptr获取的use_count是0呢shared_ptr的use_count函数会判断当前的是否存在有效的__shared_weak_count对象,如果不存在返回0。
  • 拷贝构造构造函数的时候引用计数加一__add_shared,在析构函数的时候引用计数减一__release_shared
  • 赋值函数,会先调用拷贝构造函数,所以参数的计数+1,之后再做一次swap操作,再把当前的对象返回出去。为什么等号的左值计数会减一呢?这个是因为swap之后原本的自身对象变成了临时对象,临时对象在赋值之后会自动析构。shared_ptr(__r).swap(*this);可以看做是shared_ptr<_Tp> __t(__r); __t.swap(*this);
class _LIBCPP_TYPE_VIS __shared_count
{
    __shared_count(const __shared_count&);
    __shared_count& operator=(const __shared_count&);

protected:
    long __shared_owners_;
    virtual ~__shared_count();
private:
    virtual void __on_zero_shared() _NOEXCEPT = 0;

public:
    _LIBCPP_INLINE_VISIBILITY
    explicit __shared_count(long __refs = 0) _NOEXCEPT
        : __shared_owners_(__refs) {}

#if defined(_LIBCPP_BUILDING_MEMORY) && \
    defined(_LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS)
    void __add_shared() _NOEXCEPT;
    bool __release_shared() _NOEXCEPT;
#else
    _LIBCPP_INLINE_VISIBILITY
    void __add_shared() _NOEXCEPT {
      __libcpp_atomic_refcount_increment(__shared_owners_);
    }
    _LIBCPP_INLINE_VISIBILITY
    bool __release_shared() _NOEXCEPT {
      if (__libcpp_atomic_refcount_decrement(__shared_owners_) == -1) {
        __on_zero_shared();
        return true;
      }
      return false;
    }
#endif
    _LIBCPP_INLINE_VISIBILITY
    long use_count() const _NOEXCEPT {
        return __libcpp_relaxed_load(&__shared_owners_) + 1;
    }
};

class _LIBCPP_TYPE_VIS __shared_weak_count
    : private __shared_count
{
    long __shared_weak_owners_;

public:
    _LIBCPP_INLINE_VISIBILITY
    explicit __shared_weak_count(long __refs = 0) _NOEXCEPT
        : __shared_count(__refs),
          __shared_weak_owners_(__refs) {}
protected:
    virtual ~__shared_weak_count();

public:
#if defined(_LIBCPP_BUILDING_MEMORY) && \
    defined(_LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS)
    void __add_shared() _NOEXCEPT;
    void __add_weak() _NOEXCEPT;
    void __release_shared() _NOEXCEPT;
#else
    _LIBCPP_INLINE_VISIBILITY
    void __add_shared() _NOEXCEPT {
      __shared_count::__add_shared();
    }
    _LIBCPP_INLINE_VISIBILITY
    void __add_weak() _NOEXCEPT {
      __libcpp_atomic_refcount_increment(__shared_weak_owners_);
    }
    _LIBCPP_INLINE_VISIBILITY
    void __release_shared() _NOEXCEPT {
      if (__shared_count::__release_shared())
        __release_weak();
    }
#endif
    void __release_weak() _NOEXCEPT;
    _LIBCPP_INLINE_VISIBILITY
    long use_count() const _NOEXCEPT {return __shared_count::use_count();}
    __shared_weak_count* lock() _NOEXCEPT;

    // Define the function out only if we build static libc++ without RTTI.
    // Otherwise we may break clients who need to compile their projects with
    // -fno-rtti and yet link against a libc++.dylib compiled
    // without -fno-rtti.
#if !defined(_LIBCPP_NO_RTTI) || !defined(_LIBCPP_BUILD_STATIC)
    virtual const void* __get_deleter(const type_info&) const _NOEXCEPT;
#endif
private:
    virtual void __on_zero_shared_weak() _NOEXCEPT = 0;
};

template <class _Tp, class _Dp, class _Alloc>
class __shared_ptr_pointer
    : public __shared_weak_count
{
    __compressed_pair<__compressed_pair<_Tp, _Dp>, _Alloc> __data_;
public:
    _LIBCPP_INLINE_VISIBILITY
    __shared_ptr_pointer(_Tp __p, _Dp __d, _Alloc __a)
        :  __data_(__compressed_pair<_Tp, _Dp>(__p, _VSTD::move(__d)), _VSTD::move(__a)) {}

#ifndef _LIBCPP_NO_RTTI
    virtual const void* __get_deleter(const type_info&) const _NOEXCEPT;
#endif

private:
    virtual void __on_zero_shared() _NOEXCEPT;
    virtual void __on_zero_shared_weak() _NOEXCEPT;
};

template<class _Tp>
inline
_LIBCPP_CONSTEXPR
shared_ptr<_Tp>::shared_ptr() _NOEXCEPT
    : __ptr_(0),
      __cntrl_(0)
{
}

template<class _Tp>
template<class _Yp>
shared_ptr<_Tp>::shared_ptr(_Yp* __p, typename enable_if<is_convertible<_Yp*, element_type*>::value, __nat>::type)
    : __ptr_(__p)
{
    unique_ptr<_Yp> __hold(__p);
    typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT;
    typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, _AllocT > _CntrlBlk;
    __cntrl_ = new _CntrlBlk(__p, default_delete<_Yp>(), _AllocT());
    __hold.release();
    __enable_weak_this(__p, __p);
}

template<class _Tp>
template<class _Yp>
inline
shared_ptr<_Tp>::shared_ptr(const shared_ptr<_Yp>& __r, element_type *__p) _NOEXCEPT
    : __ptr_(__p),
      __cntrl_(__r.__cntrl_)
{
    if (__cntrl_)
        __cntrl_->__add_shared();
}

template<class _Tp>
shared_ptr<_Tp>::~shared_ptr()
{
    if (__cntrl_)
        __cntrl_->__release_shared();
}

template<class _Tp>
inline
shared_ptr<_Tp>&
shared_ptr<_Tp>::operator=(const shared_ptr& __r) _NOEXCEPT
{
    shared_ptr(__r).swap(*this);
    return *this;
}

template<class _Tp>
inline
shared_ptr<_Tp>&
shared_ptr<_Tp>::operator=(shared_ptr&& __r) _NOEXCEPT
{
    shared_ptr(_VSTD::move(__r)).swap(*this);
    return *this;
}

template<class _Tp>
template<class _Yp>
inline
typename enable_if
<is_convertible<_Yp*, typename shared_ptr<_Tp>::element_type*>::value, shared_ptr<_Tp>&>::type
shared_ptr<_Tp>::operator=(const shared_ptr<_Yp>& __r) _NOEXCEPT
{
    shared_ptr(__r).swap(*this);
    return *this;
}

template<class _Tp>
inline
shared_ptr<_Tp>&
shared_ptr<_Tp>::operator=(shared_ptr&& __r) _NOEXCEPT
{
    shared_ptr(_VSTD::move(__r)).swap(*this);
    return *this;
}

例子

#include <memory>
#include <iostream>

class A {
public:
    A(std::string&& s) : str(std::move(s)) {}
    void me() { std::cout << str << std::endl; }

private:
    std::string str;
};

int main()
{
    std::shared_ptr<A> a(new A("aa")); // 调用构造函数,use_count = 1
    std::shared_ptr<A> b(a); // 调用拷贝构造函数,a和b共享一个指针,计数加1,use_count = 2
    std::shared_ptr<A> c(new A("cc")); // 调用构造函数,use_count = 1
    std::cout << "b count " << b.use_count() << std::endl;
    std::cout << "c count " << c.use_count() << std::endl;
    b = c; // 调用赋值函数,c的计数+1,原本b的计数-1
    a->me(); // aa
    c->me(); // cc
    std::cout << "a count " << a.use_count() << std::endl; // a count 1
    std::cout << "b count " << b.use_count() << std::endl; // b count 2
    std::cout << "c count " << c.use_count() << std::endl; // c count 2
    return 0;
}

weak_ptr

以下代码来来至llvm-project/libcxx/include/memory,文中只截取了部分代码。

  • weak_ptr和shared_ptr内部都使用同一个__shared_weak_count指针来管理引用计数,不同的地方是weak_ptr不能修改__shared_owners_的计数,且在操作weak_ptr对象时需要先判断是否可用(可用通过use_count或者expired来判断)
  • weak_ptr能变成shared_ptr的关键点是__shared_owners_是有效的然后对该计数+1
__shared_weak_count* __shared_weak_count::lock() _NOEXCEPT
{
    long object_owners = __libcpp_atomic_load(&__shared_owners_);
    while (object_owners != -1)
    {
        if (__libcpp_atomic_compare_exchange(&__shared_owners_, &object_owners, object_owners+1))
            return this;
    }
    return 0;
}

template<class _Tp>
class _LIBCPP_TEMPLATE_VIS weak_ptr
{
public:
    typedef _Tp element_type;
private:
    element_type*        __ptr_;
    __shared_weak_count* __cntrl_;
    ...
};

template<class _Tp> inline _LIBCPP_CONSTEXPR weak_ptr<_Tp>::weak_ptr() _NOEXCEPT
    : __ptr_(0),
      __cntrl_(0)
{
}

template<class _Tp> inline weak_ptr<_Tp>::weak_ptr(weak_ptr const& __r) _NOEXCEPT
    : __ptr_(__r.__ptr_),
      __cntrl_(__r.__cntrl_)
{
    if (__cntrl_)
        __cntrl_->__add_weak();
}

template<class _Tp>
template<class _Yp>
inline weak_ptr<_Tp>::weak_ptr(shared_ptr<_Yp> const& __r, typename enable_if<is_convertible<_Yp*, _Tp*>::value, __nat*>::type)  _NOEXCEPT
    : __ptr_(__r.__ptr_),
      __cntrl_(__r.__cntrl_)
{
    if (__cntrl_)
        __cntrl_->__add_weak();
}

template<class _Tp> inline weak_ptr<_Tp>::weak_ptr(weak_ptr&& __r) _NOEXCEPT
    : __ptr_(__r.__ptr_),
      __cntrl_(__r.__cntrl_)
{
    __r.__ptr_ = 0;
    __r.__cntrl_ = 0;
}

template<class _Tp> weak_ptr<_Tp>::~weak_ptr()
{
    if (__cntrl_)
        __cntrl_->__release_weak();
}

template<class _Tp> inline weak_ptr<_Tp>& weak_ptr<_Tp>::operator=(weak_ptr const& __r) _NOEXCEPT
{
    weak_ptr(__r).swap(*this);
    return *this;
}

template<class _Tp> inline weak_ptr<_Tp>& weak_ptr<_Tp>::operator=(weak_ptr&& __r) _NOEXCEPT
{
    weak_ptr(_VSTD::move(__r)).swap(*this);
    return *this;
}

long use_count() const _NOEXCEPT
{
    return __cntrl_ ? __cntrl_->use_count() : 0;
}

bool expired() const _NOEXCEPT
{
    return __cntrl_ == 0 || __cntrl_->use_count() == 0;
}

template<class _Tp> shared_ptr<_Tp> weak_ptr<_Tp>::lock() const _NOEXCEPT
{
    shared_ptr<_Tp> __r;
    __r.__cntrl_ = __cntrl_ ? __cntrl_->lock() : __cntrl_;
    if (__r.__cntrl_)
        __r.__ptr_ = __ptr_;
    return __r;
}

unique_ptr

以下代码来至llvm-project/libcxx/include/memory,文中只截取了部分代码。

  • 构造函数:默认构造函数管理一个空指针对象,也可以在构造函数的时候传递一个指针对象,该对象就是unique_ptr管理的指针对象,析构的时候会自动删除
  • 重载函数:重载了bool*->,在使用*->操作指针时应该先判断一下是否有效,否则操作空指针会发生段错误
  • unique_ptr主要是为了保证指针的唯一性,所以像拷贝构造函数和赋值函数是被禁用的= delete,但是右值拷贝构造函数和右值赋值函数是被允许的
template <class _Tp, class _Dp = default_delete<_Tp> >
class _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> {
public:
  typedef _Tp element_type;
  typedef _Dp deleter_type;
  typedef typename __pointer_type<_Tp, deleter_type>::type pointer;

private:
  __compressed_pair<pointer, deleter_type> __ptr_;
public:
  constexpr unique_ptr() noexcept : __ptr_(pointer()) {}
  explicit unique_ptr(_Pp __p) noexcept  : __ptr_(__p) {}
  unique_ptr(pointer __p, deleter_type __d) : __ptr_(_VSTD::move(__p), _VSTD::move(__d)) {}
  template <class _Pp, bool _Dummy = true,
            class = _EnableIfDeleterConstructible<_BadRValRefType<_Dummy>>,
            class = _EnableIfPointerConvertible<_Pp>>
  unique_ptr(_Pp __p, _BadRValRefType<_Dummy> __d) = delete;
  unique_ptr(unique_ptr&& __u) noexcept
      : __ptr_(__u.release(), _VSTD::forward<deleter_type>(__u.get_deleter())) {
  }

  ~unique_ptr() { reset(); }
  unique_ptr& operator=(nullptr_t) _NOEXCEPT {
    reset();
    return *this;
  }

  typename add_lvalue_reference<_Tp>::type
  operator*() const {
    return *__ptr_.first();
  }

  pointer operator->() const _NOEXCEPT {
    return __ptr_.first();
  }

  pointer get() const _NOEXCEPT {
    return __ptr_.first();
  }

 operator bool() const _NOEXCEPT {
    return __ptr_.first() != nullptr;
  }

  pointer release() _NOEXCEPT {
    pointer __t = __ptr_.first();
    __ptr_.first() = pointer();
    return __t;
  }

  void reset(pointer __p = pointer()) _NOEXCEPT {
    pointer __tmp = __ptr_.first();
    __ptr_.first() = __p;
    if (__tmp)
      __ptr_.second()(__tmp);
  }

  void swap(unique_ptr& __u) _NOEXCEPT {
    __ptr_.swap(__u.__ptr_);
  }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值