c++智能指针解析
智能指针的基本哲学是RAII(Resource Acquisition Is Initialization). 将内存申请放在对象构造的时候,而在对象析构的时候自动释放。
unique_ptr 把握unique含义,资源的所有权不是共享的,而是被某个对象独占的时候。当资源所有权发生转移,可以通过move或者release进行转移
shared_ptr 把握share的含义,对象的所有权是共享的,可以被拷贝
weak_ptr 把握weak的含义,是一种“弱指针”,就是指向的资源可能是不可用的(可能是个垂悬指针),需要通过lock() 或者expire() 方法检查,利用这个特性,在可能会失效的场合可以使用(例如缓存、订阅者等)。需要搭配shared_ptr使用,并且可以防止循环引用
1.auto_ptr
概述:C++98中引入auto_ptr,但是实现有缺陷(使用copy语义转移资源),现已弃用,在实际项目中不应该使用。原因如下:
auto_ptr<string> p1(new string ("auto") ; //#1
auto_ptr<string> p2; //#2
p2 = p1; //#3
查看代码
// CLASS TEMPLATE auto_ptr
template<class _Ty>
class auto_ptr
{ // wrap an object pointer to ensure destruction
public:
typedef _Ty element_type;
explicit auto_ptr(_Ty * _Ptr = nullptr) noexcept
: _Myptr(_Ptr)
{ // construct from object pointer
}
auto_ptr(auto_ptr& _Right) noexcept
: _Myptr(_Right.release())
{ // construct by assuming pointer from _Right auto_ptr
}
auto_ptr(auto_ptr_ref<_Ty> _Right) noexcept
{ // construct by assuming pointer from _Right auto_ptr_ref
_Ty * _Ptr = _Right._Ref;
_Right._Ref = nullptr; // release old
_Myptr = _Ptr; // reset this
}
template<class _Other>
operator auto_ptr<_Other>() noexcept
{ // convert to compatible auto_ptr
return (auto_ptr<_Other>(*this));
}
template<class _Other>
operator auto_ptr_ref<_Other>() noexcept
{ // convert to compatible auto_ptr_ref
_Other * _Cvtptr = _Myptr; // test implicit conversion
auto_ptr_ref<_Other> _Ans(_Cvtptr);
_Myptr = nullptr; // pass ownership to auto_ptr_ref
return (_Ans);
}
template<class _Other>
auto_ptr& operator=(auto_ptr<_Other>& _Right) noexcept
{ // assign compatible _Right (assume pointer)
reset(_Right.release());
return (*this);
}
template<class _Other>
auto_ptr(auto_ptr<_Other>& _Right) noexcept
: _Myptr(_Right.release())
{ // construct by assuming pointer from _Right
}
auto_ptr& operator=(auto_ptr& _Right) noexcept
{ // assign compatible _Right (assume pointer)
reset(_Right.release());
return (*this);
}
auto_ptr& operator=(auto_ptr_ref<_Ty> _Right) noexcept
{ // assign compatible _Right._Ref (assume pointer)
_Ty * _Ptr = _Right._Ref;
_Right._Ref = 0; // release old
reset(_Ptr); // set new
return (*this);
}
~auto_ptr() noexcept
{ // destroy the object
delete _Myptr;
}
_NODISCARD _Ty& operator*() const noexcept
{ // return designated value
#if _ITERATOR_DEBUG_LEVEL == 2
_STL_VERIFY(_Myptr, "auto_ptr not dereferencable");
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */
return (*get());
}
_NODISCARD _Ty * operator->() const noexcept
{ // return pointer to class object
#if _ITERATOR_DEBUG_LEVEL == 2
_STL_VERIFY(_Myptr, "auto_ptr not dereferencable");
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */
return (get());
}
_NODISCARD _Ty * get() const noexcept
{ // return wrapped pointer
return (_Myptr);
}
_Ty * release() noexcept
{ // return wrapped pointer and give up ownership
_Ty * _Tmp = _Myptr;
_Myptr = nullptr;
return (_Tmp);
}
void reset(_Ty * _Ptr = nullptr)
{ // destroy designated object and store new pointer
if (_Ptr != _Myptr)
delete _Myptr;
_Myptr = _Ptr;
}
private:
_Ty * _Myptr; // the wrapped object pointer
};
template<>
class auto_ptr<void>
{
public:
typedef void element_type;
};
#endif /* _HAS_AUTO_PTR_ETC */
2.unique_ptr
概述:
unique_ptr,是用于取代c++98的auto_ptr的产物,在c++98的时候还没有移动语义(move semantics)的支持,因此对于auto_ptr的控制权转移的实现没有核心元素的支持,但是还是实现了auto_ptr的移动语义,这样带来的一些问题是拷贝构造函数和复制操作重载函数不够完美,具体体现就是把auto_ptr作为函数参数,传进去的时候控制权转移,转移到函数参数,当函数返回的时候并没有一个控制权移交的过程,所以过了函数调用则原先的auto_ptr已经失效了.在c++11当中有了移动语义,使用move()把unique_ptr传入函数,这样你就知道原先的unique_ptr已经失效了.移动语义本身就说明了这样的问题.再一个,auto_ptr不支持传入deleter,所以只能支持单对象(delete object),而unique_ptr对数组类型有偏特化重载,并且还做了相应的优化,比如用[]访问相应元素等;
unique_ptr 是一个独享所有权的智能指针,它提供了严格意义上的所有权,包括:
1、拥有它指向的对象
2、无法进行复制构造,无法进行复制赋值操作。即无法使两个unique_ptr指向同一个对象。但是可以进行移动构造和移动赋值操作
3、保存指向某个对象的指针,当它本身被删除释放的时候,会使用给定的删除器释放它指向的对象
unique_ptr 可以实现如下功能:
1、为动态申请的内存提供异常安全
2、将动态申请的内存所有权传递给某函数
3、从某个函数返回动态申请内存的所有权
4、在容器中保存指针
5、auto_ptr 应该具有的功能
显示移动唯一指针所有权的关系图。
unique_ptr 在 C++ 标准库的 标头中定义。 它的效率与原始指针完全相同,可用于 C++ 标准库容器。 向 C++ 标准库容器添加 实例非常高效,因为 的移动构造函数无需 unique_ptrunique_ptr 复制操作;
查看代码
// CLASS TEMPLATE unique_ptr SCALAR
template<class _Ty,
class _Dx> // = default_delete<_Ty>
class unique_ptr
: public _Unique_ptr_base<_Ty, _Dx>
{ // non-copyable pointer to an object
public:
typedef _Unique_ptr_base<_Ty, _Dx> _Mybase;
typedef typename _Mybase::pointer pointer;
typedef _Ty element_type;
typedef _Dx deleter_type;
using _Mybase::get_deleter;
template<class _Dx2 = _Dx,
_Unique_ptr_enable_default_t<_Dx2> = 0>
constexpr unique_ptr() noexcept
: _Mybase(pointer())
{ // default construct
}
template<class _Dx2 = _Dx,
_Unique_ptr_enable_default_t<_Dx2> = 0>
constexpr unique_ptr(nullptr_t) noexcept
: _Mybase(pointer())
{ // null pointer construct
}
unique_ptr& operator=(nullptr_t) noexcept
{ // assign a null pointer
reset();
return (*this);
}
template<class _Dx2 = _Dx,
_Unique_ptr_enable_default_t<_Dx2> = 0>
explicit unique_ptr(pointer _Ptr) noexcept
: _Mybase(_Ptr)
{ // construct with pointer
}
template<class _Dx2 = _Dx,
enable_if_t<is_constructible_v<_Dx2, const _Dx2&>, int> = 0>
unique_ptr(pointer _Ptr, const _Dx& _Dt) noexcept
: _Mybase(_Ptr, _Dt)
{ // construct with pointer and (maybe const) deleter&
}
template<class _Dx2 = _Dx,
enable_if_t<conjunction_v<negation<is_reference<_Dx2>>,
is_constructible<_Dx2, _Dx2>>, int> = 0>
unique_ptr(pointer _Ptr, _Dx&& _Dt) noexcept
: _Mybase(_Ptr, _STD move(_Dt))
{ // construct by moving deleter
}
template<class _Dx2 = _Dx,
enable_if_t<conjunction_v<is_reference<_Dx2>,
is_constructible<_Dx2, remove_reference_t<_Dx2>>>, int> = 0>
unique_ptr(pointer, remove_reference_t<_Dx>&&) = delete;
unique_ptr(unique_ptr&& _Right) noexcept
: _Mybase(_Right.release(),
_STD forward<_Dx>(_Right.get_deleter()))
{ // construct by moving _Right
}
template<class _Ty2,
class _Dx2,
enable_if_t<conjunction_v<negation<is_array<_Ty2>>,
is_convertible<typename unique_ptr<_Ty2, _Dx2>::pointer, pointer>,
conditional_t<is_reference_v<_Dx>, is_same<_Dx2, _Dx>, is_convertible<_Dx2, _Dx>>
>, int> = 0>
unique_ptr(unique_ptr<_Ty2, _Dx2>&& _Right) noexcept
: _Mybase(_Right.release(),
_STD forward<_Dx2>(_Right.get_deleter()))
{ // construct by moving _Right
}
#if _HAS_AUTO_PTR_ETC
template<class _Ty2,
enable_if_t<conjunction_v<is_convertible<_Ty2 *, _Ty *>,
is_same<_Dx, default_delete<_Ty>>>, int> = 0>
unique_ptr(auto_ptr<_Ty2>&& _Right) noexcept
: _Mybase(_Right.release())
{ // construct by moving _Right
}
#endif /* _HAS_AUTO_PTR_ETC */
template<class _Ty2,
class _Dx2,
enable_if_t<conjunction_v<negation<is_array<_Ty2>>,
is_assignable<_Dx&, _Dx2>,
is_convertible<typename unique_ptr<_Ty2, _Dx2>::pointer, pointer>
>, int> = 0>
unique_ptr& operator=(unique_ptr<_Ty2, _Dx2>&& _Right) noexcept
{ // assign by moving _Right
reset(_Right.release());
this->get_deleter() = _STD forward<_Dx2>(_Right.get_deleter());
return (*this);
}
unique_ptr& operator=(unique_ptr&& _Right) noexcept
{ // assign by moving _Right
if (this != _STD addressof(_Right))
{ // different, do the move
reset(_Right.release());
this->get_deleter() = _STD forward<_Dx>(_Right.get_deleter());
}
return (*this);
}
void swap(unique_ptr& _Right) noexcept
{ // swap elements
_Swap_adl(this->_Myptr(), _Right._Myptr());
_Swap_adl(this->get_deleter(), _Right.get_deleter());
}
~unique_ptr() noexcept
{ // destroy the object
if (get() != pointer())
{
this->get_deleter()(get());
}
}
_NODISCARD add_lvalue_reference_t<_Ty> operator*() const
{ // return reference to object
return (*get());
}
_NODISCARD pointer operator->() const noexcept
{ // return pointer to class object
return (this->_Myptr());
}
_NODISCARD pointer get() const noexcept
{ // return pointer to object
return (this->_Myptr());
}
explicit operator bool() const noexcept
{ // test for non-null pointer
return (get() != pointer());
}
pointer release() noexcept
{ // yield ownership of pointer
pointer _Ans = get();
this->_Myptr() = pointer();
return (_Ans);
}
void reset(pointer _Ptr = pointer()) noexcept
{ // establish new pointer
pointer _Old = get();
this->_Myptr() = _Ptr;
if (_Old != pointer())
{
this->get_deleter()(_Old);
}
}
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
};
3.shared_ptr
概述: shared_ptr 类型是 C++ 标准库中的一个智能指针,是为多个所有者可能必须管理对象在内存中的生命周期的方案设计的。 在您初始化一个 shared_ptr 之后,您可复制它,按值将其传入函数参数,然后将其分配给其他 shared_ptr 实例。 所有实例均指向同一个对象,并共享对一个“控制块”(每当新的 shared_ptr 添加、超出范围或重置时增加和减少引用计数)的访问权限。 当引用计数达到零时,控制块将删除内存资源和自身。
下图显示了指向一个内存位置的几个 shared_ptr 实例。
共享指针关系图。
查看代码
// CLASS TEMPLATE shared_ptr
template<class _Ty>
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;
#if _HAS_CXX17
using weak_type = weak_ptr<_Ty>;
#endif /* _HAS_CXX17 */
constexpr shared_ptr() noexcept
{ // construct empty shared_ptr
}
constexpr shared_ptr(nullptr_t) noexcept
{ // construct empty shared_ptr
}
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
_Setp(_Px, is_array<_Ty>{});
}
template<class _Ux,
class _Dx,
enable_if_t<conjunction_v<is_move_constructible<_Dx>,
_Can_call_function_object<_Dx&, _Ux *&>,
_SP_convertible<_Ux, _Ty>>, int> = 0>
shared_ptr(_Ux * _Px, _Dx _Dt)
{ // construct with _Px, deleter
_Setpd(_Px, _STD move(_Dt));
}
template<class _Ux,
class _Dx,
class _Alloc,
enable_if_t<conjunction_v<is_move_constructible<_Dx>,
_Can_call_function_object<_Dx&, _Ux *&>,
_SP_convertible<_Ux, _Ty>>, int> = 0>
shared_ptr(_Ux * _Px, _Dx _Dt, _Alloc _Ax)
{ // construct with _Px, deleter, allocator
_Setpda(_Px, _STD move(_Dt), _Ax);
}
template<class _Dx,
enable_if_t<conjunction_v<is_move_constructible<_Dx>,
_Can_call_function_object<_Dx&, nullptr_t&>
>, int> = 0>
shared_ptr(nullptr_t, _Dx _Dt)
{ // construct with nullptr, deleter
_Setpd(nullptr, _STD move(_Dt));
}
template<class _Dx,
class _Alloc,
enable_if_t<conjunction_v<is_move_constructible<_Dx>,
_Can_call_function_object<_Dx&, nullptr_t&>
>, int> = 0>
shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax)
{ // construct with nullptr, deleter, allocator
_Setpda(nullptr, _STD move(_Dt), _Ax);
}
template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Right, element_type * _Px) noexcept
{ // construct shared_ptr object that aliases _Right
this->_Alias_construct_from(_Right, _Px);
}
shared_ptr(const shared_ptr& _Other) noexcept
{ // construct shared_ptr object that owns same resource as _Other
this->_Copy_construct_from(_Other);
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
shared_ptr(const shared_ptr<_Ty2>& _Other) noexcept
{ // construct shared_ptr object that owns same resource as _Other
this->_Copy_construct_from(_Other);
}
shared_ptr(shared_ptr&& _Right) noexcept
{ // construct shared_ptr object that takes resource from _Right
this->_Move_construct_from(_STD move(_Right));
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
shared_ptr(shared_ptr<_Ty2>&& _Right) noexcept
{ // construct shared_ptr object that takes resource from _Right
this->_Move_construct_from(_STD move(_Right));
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
explicit shared_ptr(const weak_ptr<_Ty2>& _Other)
{ // construct shared_ptr object that owns resource *_Other
if (!this->_Construct_from_weak(_Other))
{
_THROW(bad_weak_ptr{});
}
}
#if _HAS_AUTO_PTR_ETC
template<class _Ty2,
enable_if_t<is_convertible_v<_Ty2 *, _Ty *>, int> = 0>
shared_ptr(auto_ptr<_Ty2>&& _Other)
{ // construct shared_ptr object that owns *_Other.get()
_Ty2 * _Px = _Other.get();
_Set_ptr_rep_and_enable_shared(_Px, new _Ref_count<_Ty2>(_Px));
_Other.release();
}
#endif /* _HAS_AUTO_PTR_ETC */
template<class _Ux,
class _Dx,
enable_if_t<conjunction_v<
_SP_pointer_compatible<_Ux, _Ty>,
is_convertible<typename unique_ptr<_Ux, _Dx>::pointer, element_type *>
>, int> = 0>
shared_ptr(unique_ptr<_Ux, _Dx>&& _Other)
{ // construct from unique_ptr
using _Fancy_t = typename unique_ptr<_Ux, _Dx>::pointer;
using _Raw_t = typename unique_ptr<_Ux, _Dx>::element_type *;
using _Deleter_t = conditional_t<is_reference_v<_Dx>, decltype(_STD ref(_Other.get_deleter())), _Dx>;
const _Fancy_t _Fancy = _Other.get();
if (_Fancy)
{
const _Raw_t _Raw = _Fancy;
const auto _Rx = new _Ref_count_resource<_Fancy_t, _Deleter_t>(_Fancy, _Other.get_deleter());
_Set_ptr_rep_and_enable_shared(_Raw, _Rx);
_Other.release();
}
}
~shared_ptr() noexcept
{ // release resource
this->_Decref();
}
shared_ptr& operator=(const shared_ptr& _Right) noexcept
{ // assign shared ownership of resource owned by _Right
shared_ptr(_Right).swap(*this);
return (*this);
}
template<class _Ty2>
shared_ptr& operator=(const shared_ptr<_Ty2>& _Right) noexcept
{ // assign shared ownership of resource owned by _Right
shared_ptr(_Right).swap(*this);
return (*this);
}
shared_ptr& operator=(shared_ptr&& _Right) noexcept
{ // take resource from _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
template<class _Ty2>
shared_ptr& operator=(shared_ptr<_Ty2>&& _Right) noexcept
{ // take resource from _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
#if _HAS_AUTO_PTR_ETC
template<class _Ty2>
shared_ptr& operator=(auto_ptr<_Ty2>&& _Right)
{ // assign ownership of resource pointed to by _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
#endif /* _HAS_AUTO_PTR_ETC */
template<class _Ux,
class _Dx>
shared_ptr& operator=(unique_ptr<_Ux, _Dx>&& _Right)
{ // move from unique_ptr
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
void swap(shared_ptr& _Other) noexcept
{ // swap pointers
this->_Swap(_Other);
}
void reset() noexcept
{ // release resource and convert to empty shared_ptr object
shared_ptr().swap(*this);
}
template<class _Ux>
void reset(_Ux * _Px)
{ // release, take ownership of _Px
shared_ptr(_Px).swap(*this);
}
template<class _Ux,
class _Dx>
void reset(_Ux * _Px, _Dx _Dt)
{ // release, take ownership of _Px, with deleter _Dt
shared_ptr(_Px, _Dt).swap(*this);
}
template<class _Ux,
class _Dx,
class _Alloc>
void reset(_Ux * _Px, _Dx _Dt, _Alloc _Ax)
{ // release, take ownership of _Px, with deleter _Dt, allocator _Ax
shared_ptr(_Px, _Dt, _Ax).swap(*this);
}
using _Mybase::get;
template<class _Ty2 = _Ty,
enable_if_t<!disjunction_v<is_array<_Ty2>, is_void<_Ty2>>, int> = 0>
_NODISCARD _Ty2& operator*() const noexcept
{ // return reference to resource
return (*get());
}
template<class _Ty2 = _Ty,
enable_if_t<!is_array_v<_Ty2>, int> = 0>
_NODISCARD _Ty2 * operator->() const noexcept
{ // return pointer to resource
return (get());
}
template<class _Ty2 = _Ty,
class _Elem = element_type,
enable_if_t<is_array_v<_Ty2>, int> = 0>
_NODISCARD _Elem& operator[](ptrdiff_t _Idx) const
{ // subscript
return (get()[_Idx]);
}
_NODISCARD _CXX17_DEPRECATE_SHARED_PTR_UNIQUE bool unique() const noexcept
{ // return true if no other shared_ptr object owns this resource
return (this->use_count() == 1);
}
explicit operator bool() const noexcept
{ // test if shared_ptr object owns a resource
return (get() != nullptr);
}
private:
template<class _Ux>
void _Setp(_Ux * _Px, true_type)
{ // take ownership of _Px
_Setpd(_Px, default_delete<_Ux[]>{});
}
template<class _Ux>
void _Setp(_Ux * _Px, false_type)
{ // take ownership of _Px
_TRY_BEGIN // allocate control block and set
_Set_ptr_rep_and_enable_shared(_Px, new _Ref_count<_Ux>(_Px));
_CATCH_ALL // allocation failed, delete resource
delete _Px;
_RERAISE;
_CATCH_END
}
template<class _UxptrOrNullptr,
class _Dx>
void _Setpd(_UxptrOrNullptr _Px, _Dx _Dt)
{ // take ownership of _Px, deleter _Dt
_TRY_BEGIN // allocate control block and set
_Set_ptr_rep_and_enable_shared(_Px, new _Ref_count_resource<_UxptrOrNullptr, _Dx>(_Px, _STD move(_Dt)));
_CATCH_ALL // allocation failed, delete resource
_Dt(_Px);
_RERAISE;
_CATCH_END
}
template<class _UxptrOrNullptr,
class _Dx,
class _Alloc>
void _Setpda(_UxptrOrNullptr _Px, _Dx _Dt, _Alloc _Ax)
{ // take ownership of _Px, deleter _Dt, allocator _Ax
using _Refd = _Ref_count_resource_alloc<_UxptrOrNullptr, _Dx, _Alloc>;
using _Alref_alloc = _Rebind_alloc_t<_Alloc, _Refd>;
using _Alref_traits = allocator_traits<_Alref_alloc>;
_Alref_alloc _Alref(_Ax);
_TRY_BEGIN // allocate control block and set
const auto _Pfancy = _Alref_traits::allocate(_Alref, 1);
_Refd * const _Pref = _Unfancy(_Pfancy);
_TRY_BEGIN
_Alref_traits::construct(_Alref, _Pref, _Px, _STD move(_Dt), _Ax);
_Set_ptr_rep_and_enable_shared(_Px, _Pref);
_CATCH_ALL
_Alref_traits::deallocate(_Alref, _Pfancy, 1);
_RERAISE;
_CATCH_END
_CATCH_ALL // allocation failed, delete resource
_Dt(_Px);
_RERAISE;
_CATCH_END
}
template<class _Ty0,
class... _Types>
friend shared_ptr<_Ty0> make_shared(_Types&&... _Args);
template<class _Ty0,
class _Alloc,
class... _Types>
friend shared_ptr<_Ty0> allocate_shared(const _Alloc& _Al_arg, _Types&&... _Args);
template<class _Ux>
void _Set_ptr_rep_and_enable_shared(_Ux * _Px, _Ref_count_base * _Rx)
{ // take ownership of _Px
this->_Set_ptr_rep(_Px, _Rx);
_Enable_shared_from_this(*this, _Px);
}
void _Set_ptr_rep_and_enable_shared(nullptr_t, _Ref_count_base * _Rx)
{ // take ownership of nullptr
this->_Set_ptr_rep(nullptr, _Rx);
}
};
4.weak_ptr
概述: weak_ptr是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源(也就是shared_ptr的管理的资源)已经不复存在。weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。
weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr
查看代码
// CLASS TEMPLATE weak_ptr
template<class _Ty>
class weak_ptr
: public _Ptr_base<_Ty>
{ // class for pointer to reference counted resource
public:
constexpr weak_ptr() noexcept
{ // construct empty weak_ptr object
}
weak_ptr(const weak_ptr& _Other) noexcept
{ // construct weak_ptr object for resource pointed to by _Other
this->_Weakly_construct_from(_Other);
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr(const shared_ptr<_Ty2>& _Other) noexcept
{ // construct weak_ptr object for resource owned by _Other
this->_Weakly_construct_from(_Other);
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr(const weak_ptr<_Ty2>& _Other) noexcept
{ // construct weak_ptr object for resource pointed to by _Other
this->_Weakly_construct_from(_Other.lock());
}
weak_ptr(weak_ptr&& _Other) noexcept
{ // move construct from _Other
this->_Move_construct_from(_STD move(_Other));
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr(weak_ptr<_Ty2>&& _Other) noexcept
{ // move construct from _Other
this->_Weakly_construct_from(_Other.lock());
_Other.reset();
}
~weak_ptr() noexcept
{ // release resource
this->_Decwref();
}
weak_ptr& operator=(const weak_ptr& _Right) noexcept
{ // assign from _Right
weak_ptr(_Right).swap(*this);
return (*this);
}
template<class _Ty2>
weak_ptr& operator=(const weak_ptr<_Ty2>& _Right) noexcept
{ // assign from _Right
weak_ptr(_Right).swap(*this);
return (*this);
}
weak_ptr& operator=(weak_ptr&& _Right) noexcept
{ // move assign from _Right
weak_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
template<class _Ty2>
weak_ptr& operator=(weak_ptr<_Ty2>&& _Right) noexcept
{ // move assign from _Right
weak_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
template<class _Ty2>
weak_ptr& operator=(const shared_ptr<_Ty2>& _Right) noexcept
{ // assign from _Right
weak_ptr(_Right).swap(*this);
return (*this);
}
void reset() noexcept
{ // release resource, convert to null weak_ptr object
weak_ptr().swap(*this);
}
void swap(weak_ptr& _Other) noexcept
{ // swap pointers
this->_Swap(_Other);
}
_NODISCARD bool expired() const noexcept
{ // return true if resource no longer exists
return (this->use_count() == 0);
}
_NODISCARD shared_ptr<_Ty> lock() const noexcept
{ // convert to shared_ptr
shared_ptr<_Ty> _Ret;
(void) _Ret._Construct_from_weak(*this);
return (_Ret);
}
};
其他参考:https://changkun.de/modern-cpp/zh-cn/05-pointers/
http://c.biancheng.net/view/7898.html
http://c.biancheng.net/view/1480.html
https://www.cyhone.com/articles/right-way-to-use-cpp-smart-pointer/
https://veifi.com/?p=57
*******https://mp.weixin.qq.com/s/wiyYDxPXhYYVnonFmDrsLg******
https://mp.weixin.qq.com/s?__biz=Mzg4NjU1ODM2Nw==&mid=2247493822&idx=1&sn=6eee4d158463b29182ffb394640d93d5&chksm=cf95734ef8e2fa58ad4144ec12b57f7e962a687f98a0de09c01db797276d1eb8dc0b089adbd9&cur_album_id=1760349290872225793&scene=189#wechat_redirect