智能指针的释放_浅析C++智能指针和enable_shared_from_this 机制

大家好,我是小牛,今天跟聊一下 BAT 面试 C++ 开发工程师必问的一个考点:智能指针。

小艾:你昨晚面 C++ 去了?

小牛:对啊,不是这个厂主要技术栈都是 C++ 嘛,我就面去了。

小艾:问了点啥啊?

小牛:BAT 这 C++ 问的都差不多,又问智能指针了。

小艾:那来讲讲呗。

小牛:来。

智能指针的引入

大家都知道,指针是 C++ 中非常重要的一部分,大家在初期学习 C++ 的时候一定学过类似这样的指针方式。

int  *ptr;

这种指针也被称为裸指针。但是使用裸指针会存在一些不足

  1. 如果使用裸指针分配内存后,忘记手动释放资源,会出现内存泄漏。

  2. 如果使用多个裸指针指向同一资源,其中一个指针对资源进行释放,其它指针成为空悬指针,如果再次释放会存在不可预测的错误。30f6bcd80d77b50d1da2bc18cd1de60f.png上图中当 sp1 把资源释放后,sp2 成了空悬指针。空悬指针指的是指针所指向的对象已经释放的时候自身却没有被置为 nullptr。sp1 通过 free/delete 释放资源的内存时,内存不会立刻被系统回收,而是状态改变为可被其它地方申请的状态。这时当再次操作 sp2,这块内存可能被其它地方申请了,而具体被谁申请了是不确定的,因此可能导致的错误也是不可预测的。

  3. 如果程序异常退出时,裸指针的释放资源的代码未能执行,也会造成内存泄漏。

为了改善裸指针的不足,确保资源的分配和释放是配对的,开发者提出了智能指针。智能指针主要是对裸指针进行了一次面向对象的封装,在构造函数中初始化资源地址,在析构函数中释放资源。 当资源应该被释放时,指向它的智能指针可以确保自动地释放它。

C++ 库中,为智能指针提供了不带引用计数和带引用计数的两种方案。

引用计数用于表示有多少智能指针引用同一资源。不带引用计数的智能指针采用独占资源的方式,而带引用计数的智能指针则可以同时多个指向同一资源。下面介绍一下它们的主要特点区别

f8b33bc59c042128b4e013c3d4f738ef.png
智能指针的分类

不带引用计数的智能指针

不带引用计数的智能指针包括 auto_ptrscoped_ptrunique_ptr 三种指针。

9e3109f6d6474aab8b8645270dbeaa1c.png
不带引用计数的智能指针
1. auto_ptr:

我们先来看个例子:

#include
int main(){
 auto_ptr<int>  ptr(new int(6));//定义auto_ptr指针ptr
 auto_ptr<int>  ptr1(ptr);  //拷贝构造ptr定义ptr1
 *ptr=8;//对空指针ptr赋值会产生不可预料的错误
 return 0;
}

开始时 ptr 指向资源,一个整型数字6,当用 ptr1 拷贝构造 ptr 时,ptr1 指向资源,而 ptr 则指向 nullptr。下一行程序中如果对空指针 ptr 赋值 8,将会产生不可预料的错误。

下图表示 auto_ptr 指针对资源的指向过程。

116ff8d022f410dff1b3e49c1357ae44.png
auto_ptr

使用拷贝构造时,如果只有最后一个 auto_ptr 持有资源,其余 auto_ptr 持有的资源会被置为 nullptr

因此需要注意,不能在容器中使用 auto_ptr,当容器发生拷贝时,原容器中 auto_ptr 持有的资源会置 nullptr

下面我们再来看一下 auto_ptr 的部分源码和部分解析:

template<class _Ty>class auto_ptr
{  
public:
 typedef _Ty element_type;

 explicit auto_ptr(_Ty * _Ptr=nullptr) noexcept
     : _Myptr(_Ptr)//初始化列表{ //构造函数
     }

 auto_ptr(auto_ptr& _Right) noexcept
  : _Myptr(_Right.release())
  { //拷贝构造函数,会调用release()函数
  }
  
 _Ty * release() noexcept{
            /*使用拷贝构造时,最后一个auto_ptr持有资源,
   其余被置为nullptr*/ 
  _Ty * _Tmp = _Myptr;
  _Myptr = nullptr;
  return (_Tmp);
  }
private:
 _Ty * _Myptr;//指向资源 
};

当试图调用 auto_ptr 的拷贝构造函数时,在初始化列表中调用了 release() 函数,release()

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值