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_);
}
};