Smart Pointers源码解读
作者:互联网
智能指针是基于RAII的理念设计的一个资源的封装,能让类不直接管理资源,从而减少错误发生(忘记释放)。
1.unique_ptr
智能指针的理解要和资源的所有权相联系。unique_ptr代表的是独占的所有权(exclusive ownership),所封装的指针不能与其他共享,否则double free。
1.1.unique_ptr实现
unique_ptr主要的组成是一个所管理的指针,一个可以自定义的deleter, 而且move only(毕竟不能共享指针)。是一个处理low-level和非RAII的好方法。
原理:
unique_ptr的声明
template <typename _Tp, typename _Tp_Deleter = default_delete<_Tp> >
class unique_ptr;
unique_ptr中禁止拷贝
// Disable copy from lvalue.
unique_ptr(const unique_ptr&) = delete;
template<typename _Up, typename _Up_Deleter>
unique_ptr(const unique_ptr<_Up, _Up_Deleter>&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
template<typename _Up, typename _Up_Deleter>
unique_ptr& operator=(const unique_ptr<_Up, _Up_Deleter>&) = delete;
deleter
template<typename _Tp>
struct default_delete<_Tp>
{
default_delete() {}
template<typename _Up>
default_delete(const default_delete<_Up>&) { }
void operator()(_Tp* __ptr) const {
static_assert(sizeof(_Tp)>0, "can't delete pointer to incomplete type");
delete __ptr;
}
};
此外还有一套针对array的定义,这里使用了template的specialization技法,输入的是array的话会调用这个类。https://stackoverflow.com/questions/19923353/multiple-typename-arguments-in-c-template。
template<typename _Tp, typename _Tp_Deleter>
class unique_ptr<_Tp[], _Tp_Deleter>
移动构造,release能获得unique_ptr所管理指针,并释放所有权
// Move constructors.
unique_ptr(unique_ptr&& __u)
: _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) { }
__tuple_type _M -> typedef std::tuple<_Tp*, _Tp_Deleter> __tuple_type;
pointer get() const
{ return std::get<0>(_M_t); }
typename std::add_lvalue_reference<deleter_type>::type
get_deleter()
{ return std::get<1>(_M_t); }
pointer release()
{
pointer __p = get();
std::get<0>(_M_t) = 0; // nullify 所管理指针
return __p;
}
析构函数
~unique_ptr() { reset(); }
// 替换所管理的指针,如果没有参数,就是与一个空指针替换
reset(pointer __p = pointer()) {
if (__p != get()) { // unique_ptr为空时不会释放
get_deleter()(get()); // 等同deleter(ptr), 使用deleter释放ptr
std::get<0>(_M_t) = __p;
}
}
1.2.make_unique实现
unique_ptr
forward + variadic template(并不是pack expression,所以c++14就有make_unique)
/// std::make_unique for single objects
template<typename _Tp, typename... _Args>
inline typename _MakeUniq<_Tp>::__single_object
make_unique(_Args&&... __args)
{ return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
1.3.unique_ptr使用
所有权转换的例子
// a function consuming a unique_ptr can take it by value or by rvalue reference
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
p->bar();
return p;
}
int main() {
auto p = std::make_unique<D>(); // p is a unique_ptr that owns a D
auto q = pass_through(std::move(p));
assert(!p); // now p owns nothing and holds a null pointer
q->bar(); // and q owns the D object
}
1.3.1.自定义deleter
2.shared_ptr
一种管理可共享资源的智能指针,这就是说有多个shared_ptr指向同一个指针,并存在一个计数,当计数为0时后才释放资源。
2.0.shared_ptr和weak_ptr
解决成环问题所以引入了weak_ptr,只增加weak_count不增加use_count
https://stackoverflow.com/questions/4984381/shared-ptr-and-weak-ptr-differences
class A { shared_ptr<B> b; ... };
class B { shared_ptr<A> a; ... };
shared_ptr<A> x(new A); // +1
x->b = new B;
x->b->a = x; // +1
// Ref count of 'x' is 2.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, there will be a memory leak:
// 2 is decremented to 1, and so both ref counts will be 1.
// (Memory is deallocated only when ref count drops to 0)
2.1.shared_ptr实现
原理
shared_ptr包含了资源指针和一个计数的内部类,在计数类__shared_count中,包含保存引用计数,弱引用计数还有一个指向deleter和资源指针的_Sp_counted_base。_Sp_counted_ptr是对_Sp_counted_base的封装。
2.1.1.shared_ptr和__shared_ptr
shared_ptr只是__shared_ptr的简单封装,而__shared_ptr包含了资源指针和一个计数类__shared_count。 __shared_count负责资源计数,释放并包含deleter。
// __shared_ptr的成员
element_type* _M_ptr; // Contained pointer.
__shared_count<_Lp> _M_refcount; // Reference counter.拥有deleter和资源指针
shared_ptr只是__shared_ptr的简单封装
// Construct a shared_ptr that owns the pointer __p.
template<typename _Tp1>
explicit shared_ptr(_Tp1* __p)
: __shared_ptr<_Tp>(__p) { }
__shared_ptr包含资源的指针和一个栈上的计数对象__shared_count,__shared_ptr不负责_M_ptr的释放,这些活是由__shared_count来负责的。
// __shared_ptr的声明
template<typename _Tp, _Lock_policy _Lp>
class __shared_ptr
: public __shared_ptr_access<_Tp, _Lp> {/* 省略*/}
// __shared_ptr 的成员变量
element_type* _M_ptr; // Contained pointer.
__shared_count<_Lp> _M_refcount; // Reference counter.拥有deleter和资源指针
// __shared_ptr 的析构函数
~__shared_ptr() = default;
__shared_ptr的构造函数之一
template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>>
__shared_ptr(_Yp* __p, _Deleter __d)
: _M_ptr(__p), _M_refcount(__p, std::move(__d)) // _M_refcount拥有deleter和资源指针
{
static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
"deleter expression d(p) is well-formed");
_M_enable_shared_from_this_with(__p);
}
2.1.2.__shared_ptr_access
__shared_ptr的父类__shared_ptr_access主要负责重载解引用和->操作符。
using element_type = _Tp;
element_type&
operator*() const noexcept
{
__glibcxx_assert(_M_get() != nullptr); // 会对是否为空指针进行判断。
return *_M_get();
}
2.1.3.__shared_count
__shared_count是shared_ptr的计数模块,也是真正管理释放的部分(或者说_Sp_counted_base更准确)。用有成员变量
_Sp_counted_base<_Lp>* _M_pi;
__shared_count的构造函数
template<_Lock_policy _Lp>
class __shared_count{/* 省略*/}
// _Sp_counted_base<_Lp>* _M_pi;
template<typename _Ptr>
explicit __shared_count(_Ptr __p) : _M_pi(0) {
__try {
// _Sp_counted_base<_Lp>* _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
_M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
}
__catch(...) {
delete __p;
__throw_exception_again;
}
}
__shared_count的析构函数
~__shared_count() noexcept
{
if (_M_pi != nullptr)
_M_pi->_M_release(); // use_count--, 如果use_count等于1,清理资源。
}
针对_M_pi_, 其可能是Sp_counted_deleter或者_Sp_counted_ptr的多态表现。
Sp_counted_deleter在_Sp_counted_ptr的基础外多了deleter和allocator
// 自定义deleter时的__shared_count的构造函数
// ::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a)); // placement new, 在已分配的内存__mem上再分配
// _Sp_counted_base<_Lp>* _M_pi = __mem;
template<typename _Ptr, typename _Deleter, typename _Alloc>
__shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0)
{
typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
__try
{
typename _Sp_cd_type::__allocator_type __a2(__a);
auto __guard = std::__allocate_guarded(__a2);
_Sp_cd_type* __mem = __guard.get();
::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a));
_M_pi = __mem;
__guard = nullptr;
}
__catch(...)
{
__d(__p); // Call _Deleter on __p.
__throw_exception_again;
}
}
2.1.4._Sp_counted_base
_Sp_counted_base的成员函数
_Atomic_word _M_use_count; // #shared
_Atomic_word _M_weak_count; // #weak + (#shared != 0)
_Sp_counted_base的构造函数和析构函数
template<_Lock_policy _Lp = __default_lock_policy>
class _Sp_counted_base
: public _Mutex_base<_Lp> {/* 省略*/}
// _Sp_counted_base的构造函数
_Sp_counted_base() noexcept
: _M_use_count(1), _M_weak_count(1) { }
// _Sp_counted_base的析构函数
virtual
~_Sp_counted_base() noexcept
{ }
_Sp_counted_base的资源释放函数
// Called when _M_use_count drops to zero, to release the resources
// managed by *this.
virtual void
_M_dispose() noexcept = 0;
void
_M_release() noexcept
{
// Be race-detector-friendly. For more info see bits/c++config.
_GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
{
_GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
_M_dispose();
// There must be a memory barrier between dispose() and destroy()
// to ensure that the effects of dispose() are observed in the
// thread that runs destroy().
// See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
if (_Mutex_base<_Lp>::_S_need_barriers)
{
__atomic_thread_fence (__ATOMIC_ACQ_REL);
}
// Be race-detector-friendly. For more info see bits/c++config.
_GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count,
-1) == 1)
{
_GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
_M_destroy();
}
}
}
_Sp_counted_ptr 和 _Sp_counted_deleter
// Counted ptr with no deleter or allocator support
template<typename _Ptr, _Lock_policy _Lp>
class _Sp_counted_ptr final : public _Sp_counted_base<_Lp> {/* 省略*/}
// _Sp_counted_ptr的释放函数
virtual void
_M_dispose() noexcept
{ delete _M_ptr; }
virtual void
_M_destroy() noexcept
{ delete this; }
// Support for custom deleter and/or allocator
template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_deleter final : public _Sp_counted_base<_Lp> {/* 省略*/}
_Sp_counted_deleter的释放
// _Impl类是利用EBO的一种实现,没看明白
~_Sp_counted_deleter() noexcept { }
virtual void
_M_dispose() noexcept
{ _M_impl._M_del()(_M_impl._M_ptr); }
virtual void
_M_destroy() noexcept
{
__allocator_type __a(_M_impl._M_alloc());
__allocated_ptr<__allocator_type> __guard_ptr{ __a, this };
this->~_Sp_counted_deleter();
}
2.2.Aliasing constructor
// Aliasing constructor
/**
* @brief Constructs a %shared_ptr instance that stores @a __p
* and shares ownership with @a __r.
* @param __r A %shared_ptr.
* @param __p A pointer that will remain valid while @a *__r is valid.
* @post get() == __p && use_count() == __r.use_count()
*
* This can be used to construct a @c shared_ptr to a sub-object
* of an object managed by an existing @c shared_ptr.
*
* @code
* shared_ptr< pair<int,int> > pii(new pair<int,int>());
* shared_ptr<int> pi(pii, &pii->first);
* assert(pii.use_count() == 2);
* @endcode
*/
template<typename _Yp>
shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept
: __shared_ptr<_Tp>(__r, __p) { }
// template<typename _Tp, _Lock_policy _Lp = __default_lock_policy> class __shared_ptr;
template<typename _Yp>
__shared_ptr(const __shared_ptr<_Yp, _Lp>& __r,
element_type* __p) noexcept
_M_ptr(__p), _M_refcount(__r._M_refcount) // never throws
}
一个shared_ptr的特殊用法,指向类的成员,并增加类的引用计数,来增加使用成员类时的生命周期
struct Bar {
// some data that we want to point to
};
struct Foo {
Bar bar;
};
shared_ptr<Foo> f = make_shared<Foo>(some, args, here);
shared_ptr<Bar> specific_data(f, &f->bar);
// ref count of the object pointed to by f is 2
f.reset();
// the Foo still exists (ref cnt == 1)
// so our Bar pointer is still valid, and we can use it for stuff
some_func_that_takes_bar(specific_data);
2.3.进行使用make_shared
- new和delete对应
- cache locality
用同个malloc申请内存给control block(计数模块)和资源 -> 在相邻地址
3.weak_ptr
标签:__,count,Pointers,Sp,counted,源码,shared,ptr,Smart 来源: https://www.cnblogs.com/linsinan1995/p/13382719.html