shared_ptr
What is std::shared_ptr<>
shared_ptr是c++11提出的一种智能指针类,能够自动地删除掉相关的不再被使用的指针,它能够帮助解决内存泄漏和悬空指针的问题。
shared_ptr有一个共享对象的概念,不同的shared_ptr可以共享相同的指针,并且通过内部的引用计数机制来实现这一功能。每个shared_ptr内部都指向两个内存区域,一个是指向对象的指针,另一个就是用来做引用计数的数据。
引用计数的使用方式:
- 当有一个新的shared_ptr与指针相关联后,其引用计数递增1;
- 当一个shared_ptr对象离开作用域时,其引用计数递减1。并且在引用计数变为0的时候,它会delete那部分内存;
Creating a shared_ptr Object
创建shared_ptr对象时需要绑定一个原生指针,如下:
1 | std::shared_ptr<int> p1(new int()); |
这样,就在堆上创建了两块内存:一个是int,一个是引用计数的数据区域。
至于,要查看目前的引用计数是多少:
1 | p1.use_count(); |
另外,要将一个指针赋值给shared_ptr,我们不能采用隐式的方式,因为其构造器是采用explicit的方式,所以隐式赋值会报错,但我们可以使用std::make_shared
1 | std::shared_ptr<int> p1 = new int(); // Compile error |
Detaching the associated Raw Pointer
要使shared_ptr对象取消附加其附加指针,可以调用reset()方法。
- 无参调用reset:
1 | p1.reset(); // 递减引用计数 |
- 有参调用:
1 | p1.reset(new int(34)); //指向新的指针,引用计数变为1 |
- 使用nullptr reset
1 | p1 = nullptr; |
shared_ptr可以看作是普通指针,即我们可以对shared_ptr对象使用*和->与,也可以像其他shared_ptr对象一样进行比较。
shared_ptr and Custom Deletor
在上文说过,shared_ptr对象超出作用域的时候,会递减引用计数,当计数为0时,默认情况下会调用delete函数删除指针。但如果我们的shared_ptr指向的是一个数组,就应该使用delete[]了。
因此,为了避免默认调用的错误,我们可以自定义删除器。
1 | void deleter(Sample * x) |
当然也可以利用lambda函数或者函数对象来自定义删除器。
shared_ptr vs Pointer
与原生指针不同,shared_ptr只有以下的的操作符:
- ->, *, 比较符号;
不提供原生指针的这些操作:
- +, -, ++, —和[];
当我们创建shared_ptr对象而不分配任何值时,它就是空的。而对于原生的指针来说,它会包含一个垃圾值。因此对于shared_ptr对象,我们可以这样检查:
1 | std::shared_ptr<Sample> ptr3; |
Create shared_ptr objects carefully
在创建shared_ptr对象时,有些情况需要注意的:
- 不要使用相同的原始指针来创建多个shared_ptr对象,因为不同的shared_ptr对象并不知道它们正在与其它shared_ptr对象共享指针;
- 不要从stack中创建shared_ptr对象,因为在stack内存上调用删除操作,程序会崩溃。因此我们应该使用make_shared<>之类的;
1 | std::shared_ptr<int> ptr_1 = make_shared<int>(); |