一.简介
C++的入门坑点大家都是有目共睹的,无非就是指针的理解不深导致一些野指针,内存泄露等问题,所以就不赘述。智能指针正好能够弥补这些问题,因为它本质是存放在栈的模板对象,只是在栈内部包了一层指针。而栈在其生命周期结束时,其中的指针指向的堆内存也自然被释放了。因而实现了智能管理的效果,不需要考虑内存问题了,其实有点类似某种单例写法,程序运行结束,也不用考虑单例对象内存问题。
c++11之前的auto_ptr; c++11新加的unique_ptr, shared_ptr以及weak_ptr。
包含头文件 #include <memory>
在C++11中,引入了智能指针。主要有:unique_ptr, shared_ptr, weak_ptr。
这3种指针组件就是采用了boost里的智能指针方案。很多有用过boost智能指针的朋友,很容易地就能发现它们之间的关间。
std | boost | 功能说明 |
---|---|---|
unique_ptr | scoped_ptr | 独占指针对象,并保证指针所指对象生命周期与其一致 |
shared_ptr | shared_ptr | 可共享指针对象,可以赋值给shared_ptr或weak_ptr。 指针所指对象在所有的相关联的shared_ptr生命周期结束时结束,是强引用。 |
weak_ptr | weak_ptr | 它不能决定所指对象的生命周期,引用所指对象时,需要lock()成shared_ptr才能使用。 |
二.auto_ptr
auto_ptr是标准库里的智能指针,存在许多缺陷。
//常用一些方法
1.get():返回当前指针对象
2.release():清空当前智能指针对象,并返回类型指针。所以假如我们要正常删除,那么需要这样:
Base1*base2 = base1.release();
delete base2;
3.reset():重置智能指针,即把内存删除,且智能指针指向空,但类型不变,所以可以这样安全便捷地删除:
base1.reset();
4.auto_ptr还重载了等号操作符
auto_ptr <Base1> base2;
//将base1的控制权转交给base2,且base1清空了
base2 = base1;
因此这样就有些问题,控制权可以随便转换,但是只有一个在用,用起来会受到诸多限制。
三.unique_ptr
unique_ptr 由 C++11 引入,旨在替代不安全的 auto_ptr,它持有对对象的独有权——两个unique_ptr不能指向一个对象,即 unique_ptr 不共享它所管理的对象。unique_ptr不支持普通的拷贝或赋值操作。只能移动 unique_ptr,即对资源管理权限可以实现转移。
虽然我们不能拷贝或者赋值unique_ptr,但是可以通过调用release或reset将指针所有权从一个(非const)unique_ptr转移给另一个unique_ptr。
move函数可以是用于构造函数,也可以用于赋值函数,但需要手动显示添加,move函数用直白点的话来说就是省去拷贝构造和赋值时中间的临时对象,将资源的内存从一个对象移动到(共享也可以)另一个对象。
//将所有权从p1转移给p2,将p1置为空
unique_ptr<string> p2(p1.release());
//将所有权从p3转移到p2,reset释放了p2原来指向的内存
unique_ptr<string>p3(new string("Trex"));
p2.reset(p3.release());
//base1变成empty
unique_ptr<Base1> base1(new Base1);
unique_ptr<Base1> base2 = move(base1);
//base2变成empty
unique_ptr<Base1> base3;
base3 = move(base2);
四.shared_ptr
shared_ptr 是一个标准的共享所有权的智能指针,允许多个指针指向同一个对象;可以直接赋值和调用拷贝构造函数,且不会清空原本的智能指针。
//最安全的分配和使用动态内存的方法就是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。
shared_ptr<int> p3 = make_shared<int>(42);
shared_ptr<string> p4 = make_shared<string>(10,'9');
shared_ptr<int> p5 = make_shared<int>();
shared_ptr<Base1> base1(new Base1);
shared_ptr<Base1> base2 = base1;
shared_ptr<Base1> base3;
base3 = base2;//三个共享一个
当删除一个智能指针时,并不影响其它两个智能指针的继续使用。因为该片内存添加了一个引用计数,每shared_ptr一次,引用计数+1;每次调用析构函数,引用计数减一。直到最后一个智能指针删除,才会释放内存。
shared_ptr和unique_ptr一样可以通过move来切换控制权,这个时候是切换,不是共享了。auto_ptr和unique_ptr都可以通过move函数转换成shared_ptr类型,当然,一样是切换控制权的形式,即旧的置空。
auto_ptr<Base1> base1(new Base1);
shared_ptr<Base1> base2=move(base1);
五.weak_ptr
weak_ptr 被设计为与 shared_ptr 共同工作,可以从一个 shared_ptr 或者另一个 weak_ptr 对象构造而来。weak_ptr 是为了配合 shared_ptr 而引入的一种智能指针,它更像是 shared_ptr 的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载 operator* 和 operator-> ,因此取名为 weak,表明其是功能较弱的智能指针。它的最大作用在于协助 shared_ptr 工作,可获得资源的观测权,像旁观者那样观测资源的使用情况。观察者意味着 weak_ptr 只对 shared_ptr 进行引用,而不改变其引用计数,当被观察的 shared_ptr 失效后,相应的 weak_ptr 也相应失效。
#include < assert.h>
#include <iostream>
#include <memory>
#include <string>
using namespace std;
int main()
{
shared_ptr<int> sp(new int(10));
assert(sp.use_count() == 1);
//从shared_ptr创建weak_ptr
weak_ptr<int> wp(sp);
assert(wp.use_count() == 1);
//判断weak_ptr观察的对象是否失效
if (!wp.expired())
{
shared_ptr<int> sp2 = wp.lock();//获得一个shared_ptr
*sp2 = 100;
assert(wp.use_count() == 2);
}
assert(wp.use_count() == 1);
cout << "int:" << *sp << endl;
return 0;
}
从上面可以看到,尽管以 shared_ptr 来构造 weak_ptr,但是 weak_ptr内部的引用计数并没有什么变化