c++智慧指標解析
阿新 • • 發佈:2021-12-20
1.auto_ptr
概述:C++98中引入auto_ptr,但是實現有缺陷(使用copy語義轉移資源),現已棄用,在實際專案中不應該使用。
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
operator auto_ptr<_Other>() noexcept
{ // convert to compatible auto_ptr
return (auto_ptr<_Other>(*this));
}
template
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
auto_ptr& operator=(auto_ptr<_Other>& _Right) noexcept
{ // assign compatible _Right (assume pointer)
reset(_Right.release());
return (*this);
}
template
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
{
public:
typedef void element_type;
};
#endif /* _HAS_AUTO_PTR_ETC */
```
2.unique_ptr
概述:
unique_ptr 不共享其指標。 它不能複製到另一個 ,按值傳遞給函式,也不能在需要建立副本的任何 C++ 標準庫演算法 unique_ptr 中使用。 只能移動 unique_ptr。 這意味著,記憶體資源所有權將轉移到另一 unique_ptr,並且原始 unique_ptr 不再擁有此資源。 我們建議你將物件限制為由一個所有者所有,因為多個所有權會使程式邏輯變得複雜。 因此,當需要純 C++ 物件的智慧指標時,請使用 ,在構造 時,請使用 make_unique unique_ptrunique_ptr 程式函式。 unique_ptr
下圖演示了兩個 unique_ptr 例項之間的所有權轉換。
![](https://img2020.cnblogs.com/blog/1367831/202112/1367831-20211220181743352-1938754994.png)
顯示移動唯一指標所有權的關係圖。
unique_ptr 在 C++ 標準庫的 標頭中定義。 它的效率與原始指標完全相同,可用於 C++ 標準庫容器。 向 C++ 標準庫容器新增 例項非常高效,因為 的移動建構函式無需 unique_ptrunique_ptr 複製操作
```
// CLASS TEMPLATE unique_ptr SCALAR
template // = 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 = 0>
constexpr unique_ptr() noexcept
: _Mybase(pointer())
{ // default construct
}
template = 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 = 0>
explicit unique_ptr(pointer _Ptr) noexcept
: _Mybase(_Ptr)
{ // construct with pointer
}
template, int> = 0>
unique_ptr(pointer _Ptr, const _Dx& _Dt) noexcept
: _Mybase(_Ptr, _Dt)
{ // construct with pointer and (maybe const) deleter&
}
template>,
is_constructible<_Dx2, _Dx2>>, int> = 0>
unique_ptr(pointer _Ptr, _Dx&& _Dt) noexcept
: _Mybase(_Ptr, _STD move(_Dt))
{ // construct by moving deleter
}
template,
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>,
is_convertible::pointer, pointer>,
conditional_t, 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,
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>,
is_assignable<_Dx&, _Dx2>,
is_convertible::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 例項。
![](https://img2020.cnblogs.com/blog/1367831/202112/1367831-20211220181534345-1477718177.png)
共享指標關係圖。
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, _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,
_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,
_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,
_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,
_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
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::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::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::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, 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,
is_convertible::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, 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
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
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
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
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
void reset(_Ux * _Px)
{ // release, take ownership of _Px
shared_ptr(_Px).swap(*this);
}
template
void reset(_Ux * _Px, _Dx _Dt)
{ // release, take ownership of _Px, with deleter _Dt
shared_ptr(_Px, _Dt).swap(*this);
}
template
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, is_void<_Ty2>>, int> = 0>
_NODISCARD _Ty2& operator*() const noexcept
{ // return reference to resource
return (*get());
}
template, int> = 0>
_NODISCARD _Ty2 * operator->() const noexcept
{ // return pointer to resource
return (get());
}
template, 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
void _Setp(_Ux * _Px, true_type)
{ // take ownership of _Px
_Setpd(_Px, default_delete<_Ux[]>{});
}
template
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
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
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
friend shared_ptr<_Ty0> make_shared(_Types&&... _Args);
template
friend shared_ptr<_Ty0> allocate_shared(const _Alloc& _Al_arg, _Types&&... _Args);
template
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
概述:
有時,物件必須儲存訪問物件的基礎物件 shared_ptr而不導致 引用計數遞增。 通常,當例項之間具有迴圈引用時,會發生 shared_ptr 此情況。
最佳設計是儘可能避免指標的共享所有權。 但是,如果必須具有例項的共享 shared_ptr 所有權,請避免在例項之間迴圈引用。 當迴圈引用無法避免,或者出於某種原因更可取時,請使用 weak_ptr為一個或多個所有者提供對另一個 的弱引用 。 通過使用 ,可以建立聯接到現有相關例項集的 ,但僅在基礎記憶體資源 weak_ptrshared_ptr 仍然有效時。 weak_ptr本身不參與引用計數,因此它不能阻止引用計數進入零。 但是,可以使用 weak_ptr 嘗試獲取用於初始化它的 shared_ptr 的新副本。 如果記憶體已被刪除, weak_ptr 則 的 bool 運算子返回 false 。 如果記憶體仍然有效,則新的共享指標會遞增引用計數,並保證只要變數保留在範圍內,記憶體 shared_ptr 就有效。
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::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::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::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
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
weak_ptr& operator=(weak_ptr<_Ty2>&& _Right) noexcept
{ // move assign from _Right
weak_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
template
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);
}
};
```