介绍C++11新特性中的smart pointers 智能指针
我将先介绍智能指针,再介绍一下我的小程序。
在实际开发中,我们常常遇到因为内存资源管理不当造成的问题,比如:野指针、重复释放同一块内存、没有及时释放不再使用的内存资源,造成内存泄漏。为了让程序员摆脱内存管理的细节,智能指针就是这样的一个机制,可以自动的进行垃圾回收。
智能指针是使用RAII手法对裸指针进行的一个面向对象封装,即在构造函数中初始化资源地址,在析构函数中释放资源。智能指针保证当资源应当被释放的时候一定会释放它,这是利用了栈上的对象出作用域时自动析构这个特点。
我今天主要介绍三种智能指针,unique_ptr/shared_ptr/weak_ptr
下面先看一下U,只允许具有一个所有者。被用来取代之前的auto_ptr,一个对象只能被一个U所拥有,而不能被共享,如果需要将其所拥有的对象转移给其他U,则需要使用move语义
关于如何创建。通过这两种方法可以创建出空的指针,也可以明确其指向。
关于U的特点,第一:独享所有权,在作用域结束的时候,自动释放所关联的对象;第二,无法进行拷贝与赋值操作;第三,通过move语义进行显式的所有权转移;在这个例子中,p5将获取p4所指对空间的所有权,而p4将变成空指针。第四,作为容器元素存储在容器中。
接下来我们再来看看S,它是采用引用计数的智能指针。与U不同的是,U是独占管理权,而S是共享管理权,也就是说多个S可以共用同一块管理对象,其内部采用的是引用计数。
Shared_ptr的创建有以下两种方式,另外还可以通过C++11 标准中std::make_shared 模板函数初始化shared_ptr 智能指针。这里需要注意的是,空的 shared_ptr 指针,其初始引用计数为 0,而不是 1。
下面再来看看它的特点,S可以共享所有权,shared_ptr 模板提供有相应的拷贝构造函数和移动构造函数。
其内部采用引用计数。在拷贝的时候,引用计数+1,而在某个对象退出作用域或者释放的时候,引用计数-1,当引用计数为0的时候,会自动释放其管理的对象。S不支持数组,所以,如果用S指向一个数组的话,需要自己手动实现deleter。
通过shared_ptr解决了指针独占的问题,但也引来了引用成环的问题,让我们一起来看一下下面这个例子。(程序)这里我们有两个类,class A和class B,每个类中包含一个指向对方类型的智能指针作为成员变量,然后创建对象,输出引用计数后退出。运行试一下。
从结果我们可以看出,最后A和B的对象并没有被析构,(PPT)我们先定义了pa和pb增加了两条引用,再调用函数set_ptr后又增加了两条引用,函数返回时,pa和pb被销毁,也就是1和2两条引用断开,但3和4依旧存在,每一个的引用计数都不为0,无法自动析构。
解决这种情况就可以用到另一个智能指针weak_ptr, 它是结合 shared_ptr 使用的智能指针。W的出现,主要是为了解决S的循环引用问题,和S不同的地方在于,其并不会拥有资源,也就是说不能访问对象所提供的成员函数。
关于weak_ptr指针的创建,有以下几种方式,可以创建空的W指针,利用已有的W创建新的W指针,用shared_ptr进行初始化,指向shared_ptr指针拥有的堆内存。
W的特点:
第一,weak_ptr 模板类中没有重载 * 和 -> 运算符,这也就意味着,weak_ptr 类型指针只能访问所指的堆内存,而无法修改它。
第二,不会导致堆内存空间的引用计数增加或减少。
第三,可以从一个shared_ptr或者另外一个weak_ptr对象构造,进而可以间接获取资源的弱共享权。
第四,可以通过weak_ptr.lock()来产生一个拥有访问权限的S
(程序)再来看我们刚才的例子,我们将两个类中的一个成员变量改为weak_ptr对象,(手动更改运行)从这次的结果可以看到,A和B的对象都被正常析构了,(PPT)和之前不同的是,4这条引用是通过weakptr建立的,并不增加引用计数,也就是说现在A的对象只有一个引用计数,B的有两个,函数返回时,1和2断开,此时A对象的引用计数会减为0,对象被销毁,其内部的成员变量_s_b也会被析构,导致B对象的引用计数也减为0,对象被销毁,从而解决引用成环问题。
下面是参考的一些资料。
接下来是程序部分:
我做了一个简单的图书管理系统,它具有查看、录入、删除、查找、排序这几个功能。
下面是我设计的类图,有三个类,图书类、节点类、链表类
下面是程序的时序图,举个例子,当我们选择3的时候首先向系统发送删除请求,然后调用delete()函数,向数据库发送,再从数据库中删除一条信息,之后返回系统,最后返回成功。
下面我运行一下程序。
以上就是我对智能指针的介绍。
RAII,也称为“资源获取就是初始化”,是c++等编程语言常用的管理资源、避免内存泄露的方法。它保证在任何情况下,使用对象时先构造对象,最后析构对象。
对于智能指针的使用,实际上是对所有权和生命周期的思考,一旦想明白了这两点,那对智能指针的使用也就得心应手了。
同时理解了每种智能指针背后的性能消耗、使用场景,那智能指针也不再是黑盒子和洪水猛兽。



