c++智能指针解析
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://www.icode9.com/i/l/?n=20&i=blog/1367831/202112/1367831-20211220181743352-1938754994.png)
显示移动唯一指针所有权的关系图。
unique_ptr 在 C++ 标准库的 标头中定义。 它的效率与原始指针完全相同,可用于 C++ 标准库容器。 向 C++ 标准库容器添加 实例非常高效,因为 的移动构造函数无需 unique_ptrunique_ptr 复制操作
// = 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_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,
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;
};
```