深度剖析智能指针

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度剖析智能指针相关的知识,希望对你有一定的参考价值。


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

首先来看这样一个例子:

技术分享

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

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

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

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

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

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

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

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

技术分享

技术分享

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

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

技术分享在析构函数中,只是对拥有管理权者进行了析构。在delete内存之后重置指针的方法只对这个指针有效,对其他任何指向(已释放的)内存的指针是没有作用的。所以会出现"野指针"。

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

auto_ptr的现代写法:

技术分享

技术分享

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


2.简单粗暴的scoped_ptr

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

技术分享

注:为了防拷贝和赋值

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

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


3.允许拷贝和赋值的shared_ptr

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

技术分享

技术分享

4. 简单粗暴的scoped_array

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

技术分享

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


5.允许拷贝和赋值的shared_array

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

技术分享

技术分享

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

(1)循环引用

(2)定置删除器


6.1循环引用

技术分享

技术分享

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

技术分享

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


6.2 定置删除器

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

技术分享

技术分享

技术分享

技术分享

测试结果:

技术分享


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

以上是关于深度剖析智能指针的主要内容,如果未能解决你的问题,请参考以下文章

智能指针剖析

智能指针之atuo_ptr源码剖析

STL之智能指针剖析

c++智能指针--所有的类型的解析

c++智能指针--所有的类型的解析

第28课 再论智能指针(下)