【转载】C++11智能指针中make_shared存在的必要性
【转载】原文链接:https://www.veaxen.com/c11%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88%E4%B8%ADmake_shared%E5%AD%98%E5%9C%A8%E7%9A%84%E5%BF%85%E8%A6%81%E6%80%A7.html
前言
最近在看谷歌的开源项目sfntly,然后发现了这个项目中用的是智能指针与我之前学C++的时候接触的智能指针(shared_ptr)的实现方式不同,是两个不同的角度。所以为了更好的理解sfntly里智能指针的实现思想,我先对之前学习C++11标准库的智能指针做一个总结,由于之前没有记录,所以就写下本文,方便自己以后翻出了看。
要说到C++11智能指针的实现,我觉得最好的理解方式是搞清楚make_shared的存在。本文就从make_shared开始,大概说下智能指针的实现,以及为什么要存在make_shared。
引用计数原理
C++11中的shared_ptr的定义我们截取一部分大概是这样的:
看了定义应该也容易明白shared_ptr的原理,就是用px来记录引用的对象的指针,使用pn来记录有多少个shared_ptr引用了相同对象(引用计数),当pn指向的引用计数为0时,delete px
;
C++11直接使用 shared_ptr<T>
和 make_shared<T>
都可以创建智能指针。但是结合前面的简单说的原理,我们来讲下他们的区别。
使用shared_ptr直接创建智能指针:
我们有下面的两个过程:
– new int
申请内存,并把指针传给shared_ptr中的px
– 为shared_ptr 的控制块另外申请一块内存,用来存放shared_ptr的控制信息,比如shared_ptr引用计数,weak_ptr引用计数。
这样把创建一个智能指针需要分两步申请内存,会存在下面两个问题:
– 当 new int
申请内存成功,但引用计数内存申请失败时,很可能造成内存泄漏。
– 内存分配是一个消耗性能的过程,分两次分配内存,意味着性能会下降
为了解决直接使用shared_ptr创建智能指针带来的问题,C++11标准库引入了make_shared:
make_shared只会申请一次内存,这块内存会大于int所占用的内存,多出的部分被用于智能指针引用计数。这样就避免了直接使用shared_ptr带来的问题。
不过make_shared并不是完美的。
前面只说到强引用计数,其实智能指针还有弱引用计数。当强引用计数为0时,释放引用的对象内存,当弱引用计数为0时,释放引用计数所占用的内存。
由于弱引用计数的存在,make_shared创建的智能指针引用的对象,可能无法得到及时的释放,只有当强/弱引用都为0时,才能释放make_shared申请的一整块内存。