写点什么

C++ 中的四种智能指针

作者:桑榆
  • 2022 年 8 月 05 日
  • 本文字数:2044 字

    阅读完需:约 7 分钟

引言:为什么需要智能指针?

C++赋予了程序员直接操控底层内存的能力,同时,也对程序员的能力提出了要求,必须要对申请的内存空间进行释放,而且释放时机也必须准确,否则就会出现内存泄露,useafterfree 等异常。寻找一种简单完美的方式解决这个问题一直是 C++程序员需要关注的,在 Android 平台上使用了 StrongPoint 的方式,相当于将原有的指针包装成一个类,通过对指针 reference 次数的管理来实现对应空间的准确释放,在 C++中则也使用了类似的方式,使用了智能指针类,通过引用计数来管理智能指针指向的内存空间,只有当指针引用计数为空时,才进行对象的销毁。

接下来,我们就来一起看看 C++的四种智能指针。

C++的四种智能指针

代码位置(参考 AOSP 代码)

www.aospxref.com/android-12.… 

基础接口

T* get();T& operator*();T* operator->();T& operator=(const T& val);T* release();void reset (T* ptr = nullptr);
复制代码


  • get()返回封装在内部的指针

  • operator*解引用原生指针

  • operator->相当于对原生指针做->操作

  • operator=指针拷贝操作

  • release 将内部封装的指针置为 nullptr,返回置空前的值

  • reset 将内部封装的指针重置为 ptr 的值

1.auto_ptr(C++98 的方案,C11 已抛弃)采用所有权模式

auto_ptr<std::string> p1 (new string ("test"));auto_ptr<std::string> p2;p2 = p1; //赋值成功,此时p2拥有原生指针的所有权,后续再使用p1指针时就会报错
复制代码

观察 auto_ptr 的赋值重载函数,会将等号右面的 point reset

#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR)template <class _Tp>struct _LIBCPP_DEPRECATED_IN_CXX11 auto_ptr_ref{    _Tp* __ptr_;};...     _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr_ref<_Tp> __p) throw()         {reset(__p.__ptr_); return *this;}
复制代码

auto_ptr 是独占的,当赋值之后,存在潜在的无法检测的内存异常。

2.unique_ptr

unique_ptr 实现独占式拥有或严格拥有概念,保证同一时间内只有一个智能指针可以指向该对象,主要为了避免资源泄露。上面的例子:

unique_ptr<std::string> p1 (new string ("test"));unique_ptr<std::string> p2;p2 = p1; //赋值失败,此时编译器会认为此操作非法,从而避免出现异常
复制代码

同样,我们来看看它的赋值重载函数,只发现了移动构造和移动赋值函数,正常的拷贝构造和赋值拷贝是被禁用的

unique_ptr& operator=(unique_ptr&& u) noexcept;template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;unique_ptr& operator=(nullptr_t) noexcept;
复制代码

3.shared_ptr(共享型,强引用)

shared_ptr 实现共享式拥有概念,多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用被销毁”时候释放。资源可以被多个指针共享,它使用计数机制来表明资源被几个指针共享。过成员函数 use_count() 来查看资源的所有者个数,调用 release() 时,当前指针会释放资源所有权,计数减一,当计数等于 0 时,资源会被释放。我们来看看其释放的过程:

__shared_weak_count* __cntrl_;//一个弱引用计数...template<class _Tp> shared_ptr<_Tp>::~shared_ptr(){    if (__cntrl_)        __cntrl_->__release_shared();}
_LIBCPP_INLINE_VISIBILITY bool __release_shared() _NOEXCEPT { if (__libcpp_atomic_refcount_decrement(__shared_owners_) == -1) {//减法操作后为-1,代表此时已经可以销毁了 __on_zero_shared(); return true; } return false; }
template <class _Tp, class _Dp, class _Alloc>void__shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared() _NOEXCEPT { __data_.first().second()(__data_.first().first()); __data_.first().second().~_Dp();//调用删除器析构,彻底释放资源}
复制代码

4.weak_ptr(弱引用)

weak_ptr 是一种不控制对象生命周期的智能指针,它指向一个 shared_ptr 管理的对象。进行该对象的内存管理的是那个强引用的 shared_ptr。weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作,它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造,,它的构造和析构不会引起引用记数的增加或减少。

weak_ptr 是用来解决 shared_ptr 相互引用时的死锁问题,如果说两个 shared_ptr 相互引用,那么这两个指针的引用计数永远不可能下降为 0,也就是资源永远不会释放。当两个智能指针都是 shared_ptr 类型的时候,析构时两个资源引用计数会减一,但是两者引用计数还是为 1,导致跳出函数时资源没有被释放(的析构函数没有被调用),解决办法:把其中一个改为 weak_ptr 就可以。

发布于: 2022 年 08 月 05 日阅读数: 87
用户头像

桑榆

关注

北海虽赊,扶摇可接;东隅已逝,桑榆非晚! 2020.02.29 加入

Android手机厂商-相机软件系统工程师 爬山/徒步/Coding

评论

发布
暂无评论
C++ 中的四种智能指针_c++_桑榆_InfoQ写作社区