1. 程式人生 > 其它 >c++智慧指標解析

c++智慧指標解析

1.auto_ptr 概述:C++98中引入auto_ptr,但是實現有缺陷(使用copy語義轉移資源),現已棄用,在實際專案中不應該使用。
點選檢視程式碼 ``` // CLASS TEMPLATE auto_ptr template 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 TEMPLATE shared_ptr template 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 TEMPLATE weak_ptr template 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); } }; ```