源码来自llvm 8.0.0的libc++,精简了一些不太重要的部分,重要的地方加了注释。目的是学习智能指针的实现原理。关于shared_ptr的线程安全问题,cppreference上的描述:
All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object. If multiple threads of execution access the same shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur; the shared_ptr overloads of atomic functions can be used to prevent the data race.
template<class _Tp>
class _LIBCPP_TEMPLATE_VIS shared_ptr // 3740
{
public:
typedef _Tp element_type;
#if _LIBCPP_STD_VER > 14
typedef weak_ptr<_Tp> weak_type;
#endif
private:
element_type* __ptr_; // 直接使用,提升性能
__shared_weak_count* __cntrl_; // 底层的引用计数
struct __nat {int __for_bool_;};
public:
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR shared_ptr() _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR shared_ptr(nullptr_t) _NOEXCEPT;
template<class _Yp>
explicit shared_ptr(_Yp* __p,
typename enable_if<is_convertible<_Yp*, element_type*>::value, __nat>::type = __nat());
~shared_ptr();
_LIBCPP_INLINE_VISIBILITY
shared_ptr& operator=(const shared_ptr& __r) _NOEXCEPT;
template<class _Yp>
typename enable_if
<
is_convertible<_Yp*, element_type*>::value,
shared_ptr&
>::type
_LIBCPP_INLINE_VISIBILITY
operator=(const shared_ptr<_Yp>& __r) _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
shared_ptr& operator=(shared_ptr&& __r) _NOEXCEPT;
template<class _Yp>
typename enable_if
<
is_convertible<_Yp*, element_type*>::value,
shared_ptr<_Tp>&
>::type
_LIBCPP_INLINE_VISIBILITY
operator=(shared_ptr<_Yp>&& __r);
_LIBCPP_INLINE_VISIBILITY
void swap(shared_ptr& __r) _NOEXCEPT;
template<class _Yp>
typename enable_if
<
is_convertible<_Yp*, element_type*>::value,
void
>::type
_LIBCPP_INLINE_VISIBILITY
reset(_Yp* __p);
_LIBCPP_INLINE_VISIBILITY
element_type* get() const _NOEXCEPT {return __ptr_;} // 直接返回__ptr_,无需到__cntrl_里才返回指针
_LIBCPP_INLINE_VISIBILITY
typename add_lvalue_reference<element_type>::type operator*() const _NOEXCEPT
{return *__ptr_;}
_LIBCPP_INLINE_VISIBILITY
element_type* operator->() const _NOEXCEPT {return __ptr_;}
_LIBCPP_INLINE_VISIBILITY
long use_count() const _NOEXCEPT {return __cntrl_ ? __cntrl_->use_count() : 0;}
_LIBCPP_INLINE_VISIBILITY
bool unique() const _NOEXCEPT {return use_count() == 1;}
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_EXPLICIT operator bool() const _NOEXCEPT {return get() != 0;}
template <class _Up>
_LIBCPP_INLINE_VISIBILITY
bool owner_before(shared_ptr<_Up> const& __p) const _NOEXCEPT
{return __cntrl_ < __p.__cntrl_;}
_LIBCPP_INLINE_VISIBILITY
bool
__owner_equivalent(const shared_ptr& __p) const
{return __cntrl_ == __p.__cntrl_;}
template<class ..._Args>
static
shared_ptr<_Tp>
make_shared(_Args&& ...__args);
template<class _Alloc, class ..._Args>
static
shared_ptr<_Tp>
allocate_shared(const _Alloc& __a, _Args&& ...__args);
static shared_ptr<_Tp> make_shared();
template<class _A0>
static shared_ptr<_Tp> make_shared(_A0&);
private:
template <class _Yp, bool = is_function<_Yp>::value>
struct __shared_ptr_default_allocator
{
typedef allocator<_Yp> type;
};
template <class _Yp>
struct __shared_ptr_default_allocator<_Yp, true>
{
typedef allocator<__shared_ptr_dummy_rebind_allocator_type> type;
};
template <class _Yp, class _OrigPtr>
_LIBCPP_INLINE_VISIBILITY
typename enable_if<is_convertible<_OrigPtr*,
const enable_shared_from_this<_Yp>*
>::value,
void>::type
__enable_weak_this(const enable_shared_from_this<_Yp>* __e,
_OrigPtr* __ptr) _NOEXCEPT
{
typedef typename remove_cv<_Yp>::type _RawYp;
if (__e && __e->__weak_this_.expired())
{
__e->__weak_this_ = shared_ptr<_RawYp>(*this,
const_cast<_RawYp*>(static_cast<const _Yp*>(__ptr)));
}
}
_LIBCPP_INLINE_VISIBILITY void __enable_weak_this(...) _NOEXCEPT {}
template <class _Up> friend class _LIBCPP_TEMPLATE_VIS shared_ptr;
template <class _Up> friend class _LIBCPP_TEMPLATE_VIS weak_ptr;
};
template<class _Tp>
inline
_LIBCPP_CONSTEXPR
shared_ptr<_Tp>::shared_ptr() _NOEXCEPT
: __ptr_(0),
__cntrl_(0)
{
}
template<class _Tp>
inline
_LIBCPP_CONSTEXPR
shared_ptr<_Tp>::shared_ptr(nullptr_t) _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>
inline
shared_ptr<_Tp>::shared_ptr(const shared_ptr& __r) _NOEXCEPT
: __ptr_(__r.__ptr_),
__cntrl_(__r.__cntrl_)
{
if (__cntrl_)
__cntrl_->__add_shared(); // 拷贝构造只是简单拷贝两个指针,再引用计数加1
}
template<class _Tp>
shared_ptr<_Tp>::~shared_ptr()
{
if (__cntrl_)
__cntrl_->__release_shared(); // __cntrl_中的引用计数减1,如果无其它引用,则执行释放
}
template<class _Tp>
inline
void
shared_ptr<_Tp>::swap(shared_ptr& __r) _NOEXCEPT
{
_VSTD::swap(__ptr_, __r.__ptr_);
_VSTD::swap(__cntrl_, __r.__cntrl_);
}
template<class _Tp>
template<class _Yp>
inline
typename enable_if
<
is_convertible<_Yp*, typename shared_ptr<_Tp>::element_type*>::value,
void
>::type
shared_ptr<_Tp>::reset(_Yp* __p)
{
shared_ptr(__p).swap(*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); // 赋值是先构造右值,再与本对象swap
return *this;
}
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, class _Dp, class _Alloc>
void
__shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT
{
typedef typename __allocator_traits_rebind<_Alloc, __shared_ptr_pointer>::type _Al;
typedef allocator_traits<_Al> _ATraits;
typedef pointer_traits<typename _ATraits::pointer> _PTraits;
_Al __a(__data_.second());
__data_.second().~_Alloc();
__a.deallocate(_PTraits::pointer_to(*this), 1);
}
template <class _Tp, class _Dp, class _Alloc>
void
__shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared() _NOEXCEPT // 核心,释放资源
{
__data_.first().second()(__data_.first().first()); // 对资源指针调用deleter
__data_.first().second().~_Dp();
}
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 // 注意:这里是从0起
: __shared_count(__refs),
__shared_weak_owners_(__refs) {}
protected:
virtual ~__shared_weak_count();
public:
_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();
}
void __release_weak() _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
long use_count() const _NOEXCEPT {return __shared_count::use_count();}
__shared_weak_count* lock() _NOEXCEPT;
private:
virtual void __on_zero_shared_weak() _NOEXCEPT = 0;
};
void
__shared_weak_count::__release_weak() _NOEXCEPT
{
// NOTE: The acquire load here is an optimization of the very
// common case where a shared pointer is being destructed while
// having no other contended references.
//
// BENEFIT: We avoid expensive atomic stores like XADD and STREX
// in a common case. Those instructions are slow and do nasty
// things to caches.
//
// IS THIS SAFE? Yes. During weak destruction, if we see that we
// are the last reference, we know that no-one else is accessing
// us. If someone were accessing us, then they would be doing so
// while the last shared / weak_ptr was being destructed, and
// that's undefined anyway.
//
// If we see anything other than a 0, then we have possible
// contention, and need to use an atomicrmw primitive.
// The same arguments don't apply for increment, where it is legal
// (though inadvisable) to share shared_ptr references between
// threads, and have them all get copied at once. The argument
// also doesn't apply for __release_shared, because an outstanding
// weak_ptr::lock() could read / modify the shared count.
if (__libcpp_atomic_load(&__shared_weak_owners_, _AO_Acquire) == 0)
{
// no need to do this store, because we are about
// to destroy everything.
//__libcpp_atomic_store(&__shared_weak_owners_, -1, _AO_Release);
__on_zero_shared_weak();
}
else if (__libcpp_atomic_refcount_decrement(__shared_weak_owners_) == -1)
__on_zero_shared_weak();
}
__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 nullptr;
}
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 // 注意:这里是从0起
: __shared_owners_(__refs) {}
_LIBCPP_INLINE_VISIBILITY
void __add_shared() _NOEXCEPT {
__libcpp_atomic_refcount_increment(__shared_owners_); // 原子操作引用计数加1
}
_LIBCPP_INLINE_VISIBILITY
bool __release_shared() _NOEXCEPT {
if (__libcpp_atomic_refcount_decrement(__shared_owners_) == -1) { // 原子操作引用计数减1,当__shared_owners_为-1的时候释放资源
__on_zero_shared(); // 注意,如果在这里另一个线程拷贝构造了这个shared_ptr,会有问题
return true;
}
return false;
}
_LIBCPP_INLINE_VISIBILITY
long use_count() const _NOEXCEPT {
return __libcpp_relaxed_load(&__shared_owners_) + 1; // 返回引用计数
}
};