336-建议用make_shared代替shared_ptr

建议用make_shared代替shared_ptr

1、shared_ptr

我们先看下面的代码:
在这里插入图片描述

shared_ptr<int> sp1(new int(10));

对于sp1来说,它的内存布局如下:

  • 指向资源的指针
  • 指向资源引用计数的指针

在这里插入图片描述

shared_ptr是继承的_Ptr_base类:
在这里插入图片描述
我们进入_Ptr_base类中:

  • 分别指向资源和引用计数资源!
    在这里插入图片描述
    进入_Ref_count_base类中:
    在这里插入图片描述
    C++11中基于CAS实现的线程安全的类型!

_Uses:表示强智能指针使用这个资源的计数!
_Weaks:表示弱智能指针使用这个资源的计数!

转换成图解如下:

在这里插入图片描述
只有uses从1减到0,智能指针shared_ptr才能析构释放其所指向的资源。

这样子,确实是存在缺陷!!!

在这里插入图片描述
这句代码,存在2个内存开辟:

  • 1、堆内存的资源 ,也就是我们想托管的资源
  • 2、引用计数对象,也是new出来的

在这里插入图片描述
那么,我们继续看下面代码:
在这里插入图片描述
拿sp1拷贝构造sp2
按理说,uses会加1,因为又有一个强智能指针指向这个资源。

拿一个弱智能指针监视观察sp1:

  • 那么weaks就会加1,只是观察的角色;
  • 观察资源的uses为不为0,如果为0,则资源已经被释放了,如果资源不为0,资源还在!
  • 没有办法直接访问对象,可以通过lock方法提升为强智能指针去访问这个资源
    在这里插入图片描述

2、shared_ptr的缺陷

shared_ptr存在的缺陷是:
在这里插入图片描述
如果这句代码的new int(10)成功了,但是new 引用计数对象的时候失败了。
在这里插入图片描述
生成对象失败,意味着shared_ptr不会再去调用它的析构函数了。造成资源泄漏了。存在这个风险。想要托管的资源泄漏了。

3、换成make_shared会怎么样?(优势)

在这里插入图片描述
在这里插入图片描述
这个好处在哪里?

意思是: 使用make_shared定义的话,把想要托管的资源和引用计数对象资源的内存合并到一块了
在这里插入图片描述
这样的话,就是new一次,要么都成功,要么都失败,不会存在托管的资源new成功而引用计数对象new失败造成智能指针对象创建失败的这种情况 了

所以,在实际开发中,我们推荐使用make_shared!

在这里插入图片描述

我们看到,make_ptr返回的就是shared_ptr,所以我们使用auto:

在这里插入图片描述

make_shared相当于是函数模板,可以直接类型实例化;

  • 这个10相当于我们原本写的new int(10),这个10也是在堆上的,只不过这个内存不需要我们自己去开辟去书写new int 了;
  • 我们只需要把10这种用户想要赋值的数据给它,然后把相应的类型进行实例化< int >,然后它就会帮我们组织底层的内存;
  • 把我们存放资源的内存和存放引用计数的内存放在一块,打包成一个结构,然后new一次,要么全成功,要么全失败。全失败的话,意味着没有开辟任何的内存,没有占用任何的内存,也就不需要析构释放了。
#include <iostream>
using namespace std;

class Test
{
public:
	Test(int a) { cout << "Test(int)" << endl; }
	Test(int a, int b) { cout << "Test(int,int)" << endl; }
};

int main()
{
	shared_ptr<int> sp1(new int(10));
	shared_ptr<Test> sp2(new Test(10));

	auto sp3 = make_shared<int>(10);
	*sp3 = 20;
	cout << *sp3 << endl;

	auto sp4 = make_shared<Test>(10);	//new Test(10);
	auto sp5 = make_shared<Test>(10, 20);	//new Test(10,20);

	return 0;
}

在这里插入图片描述
也可以这样写:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

4、make_shared的弱势

1、没有自定义的删除器(没有模板类型来接收删除器的)

,如果要自定义删除器,只能使用原始的版本了**

默认的删除器是delete,无法delete 数组或者文件了
在这里插入图片描述

2、托管的资源延迟释放

shared_ptr:

原始的使用shared_ptr:

  • 资源是资源的内存,引用计数是引用计数的内存!
    在这里插入图片描述
  • 当shared_ptr是最后一个引用该资源的智能指针时,出作用域时,uses从1减到0,就直接把内存释放掉了,哪怕这里还有很多weak_ptr在观察着,没有关系,它们只是观察引用计数。
  • 当最后一个引用该资源的强智能指针把uses从1减到0的时候,就把托管的资源释放了。

也就是说,我们原来这样使用的话:
在这里插入图片描述
在这里插入图片描述

只要该资源没有强智能指针去引用它,所有引用该资源的强智能指针出作用域了,这个new int(10)资源是一定会马上释放的。

make_shared:

如果我们现在使用的是make_shared的话,情况是什么样的?

因为这段内存现在是一起开辟的,所以也是要一起释放的。

假如现在引用该资源的所有强智能指针都出作用域了,但是引用计数对象还不能释放,因为它的weaks不为0,还有弱智能指针在观察它呢。

在这里插入图片描述
如果强智能指针把uses从1减到0,并且weaks也是0的时候,就把这块内存全部释放掉了。

如果强智能指针把uses从1减到0,但是weaks不为0,不能释放这块内存了,因为还有弱智能指针指向着,在观察呢。

在这里插入图片描述

5、C++14的make_unique

代替了C++11的unique_ptr

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liufeng2023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值