深度剖析智能指针


RALL:资源分配即初始化,定义一个类来封装资源的分配和释放,在构造函数中完成资源的分配和初始化,在析构函数中完成资源的清理。

首先来看这样一个例子:

深度剖析智能指针_第1张图片

此例子乍一看上去,new/delete匹配,并没有什么错。但就因为return的存在,使得Test()函数提前结束,并没有执行delete p。这就使得内存泄露。

内存泄露的危害:使得可用内存越来越少,下一次开辟可能不够,程序崩溃。

为解决此类问题,引入智能指针。

所谓的智能指针就是智能/自动化的管理指针所指向的动态资源的释放。

智能指针的行为类似于常规指针,重要的区别在于它负责自动释放所指向的对象。

智能指针也是模板,当我们创建一个智能指针时,需要提供指针可以指向的类型。

智能指针有:auto_ptr,scoped_ptr,shared_ptr,scoped_array,shared_array

1.auto_prt的模拟实现(以前)

注:以前的auto_ptr看起来已经实现的挺好的,多个指针指向同一块内存,并且释放的时候也正确

但是在实现的时候,会出现"野指针"。也就是所谓的"悬挂指针"。

深度剖析智能指针_第2张图片在析构函数中,只是对拥有管理权者进行了析构。在delete内存之后重置指针的方法只对这个指针有效,对其他任何指向(已释放的)内存的指针是没有作用的。所以会出现"野指针"。

为解决"野指针"问题,可以将管理权转交后,将以前的指针赋为NULL。也就是auto_ptr的现代写法。

auto_ptr的现代写法:

深度剖析智能指针_第3张图片

深度剖析智能指针_第4张图片

注:虽然此方法解决了"野指针"的问题,但是在拷贝构造和赋值后,只有一个指针有效。其他的都已为NULL,但有时候会对NULL指针进行引用,使得程序崩溃。


2.简单粗暴的scoped_ptr

scoped_ptr不允许拷贝构造和赋值,在C++11标准中叫unique_ptr

深度剖析智能指针_第5张图片

注:为了防拷贝和赋值

(1)只将拷贝构造和赋值函数声明不定义

(2)将拷贝构造和赋值函数声明为private或protected,防止别人搞破坏


3.允许拷贝和赋值的shared_ptr

shared_ptr是通过一个引用计数来记录该块空间被共享了几次,只有当计数器为0时才被释放。

深度剖析智能指针_第6张图片

深度剖析智能指针_第7张图片

4. 简单粗暴的scoped_array

scoped_array和scoped_ptr类似,是为了防拷贝和赋值。但是scoped_array是对数组来说的,因此在析构时要特别注意,应该使用delete[]来释放内存。

深度剖析智能指针_第8张图片

注:scoped_ptr是为了防拷贝和赋值。因此只将拷贝和赋值声明而不定义,并且将拷贝和赋值声明为private或者protected,防止他人搞破坏。


5.允许拷贝和赋值的shared_array

shared_array和shared_ptr类似。也是使用了一个引用计数。但是shared_array是对数组来说的。因此在析构时应使用delete[]。

深度剖析智能指针_第9张图片

深度剖析智能指针_第10张图片

6.现代版的shared_ptr看起来不错,但是会出现以下几个问题

(1)循环引用

(2)定置删除器


6.1循环引用

深度剖析智能指针_第11张图片

为了解决循环引用,应该使用弱指针weak_ptr(防止引用计数的增加)

注:所谓的weak_ptr就是用来服务shared_ptr。将一个weak_ptr绑定一个shared_ptr上不会改变shared_ptr的引用计数。


6.2 定置删除器

我们都只到shared_ptr只能释放new开辟出来的空间。而对于malloc开辟出来的空间,以及fopen打开的文件不能处理。为了能够处理各种情况,引入定置删除器。而定置删除器的实现是通过operator()即重载()来实现的。

深度剖析智能指针_第12张图片

测试结果:


注:任何情况下都不要使用auto_ptr。

你可能感兴趣的:(指针,智能)