0
点赞
收藏
分享

微信扫一扫

C++ 中的四种智能指针

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

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 就可以。

举报

相关推荐

C++中的智能指针

C++智能指针

C++——智能指针

【C++】智能指针

C++ 智能指针

0 条评论