C++——C++11(2)

我在我的C++异常博客中曾提到,对于异常的处理经常会导致内存泄漏问题,
一种解决方法是异常的重新抛出,还有一种就是RAII,那么RAII的思想体现
在C++中就是智能指针,所以接下来我将简单的介绍,什么是RAII,以及什
么是智能指针。

1. 初识智能指针

在学C++的人,还没有接触智能指针的时候,就会想智能指针到底是什么啊?它真的是智能的吗?其实智能指针只是人们给它起了个这样的名字,它并不是智能的。
我们首先来解决异常博客中,如何使用RAII的思想很好的解决内存泄漏问题:
在这里插入图片描述
在这里插入图片描述
可以看到在程序执行中,只是开辟了空间,而没有释放。原因就是异常抛出后,如果有接收异常的地方,执行流会直接跳跃到匹配的catch中,而不执行中间栈帧的后续代码(但是会销毁中途的栈帧),而开辟空间是在堆上,自然也就无法释放了。接下来给出RAII思想解决内存泄漏问题:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到我们确实能够很好的将申请的资源释放,并且不需要我们自己手动释放。利用的原理也是当栈帧结束的时候,会调用栈帧中的自定义类的对象的析构函数,而我们利用这一点,正好可以将资源释放。而这可以说是RAII,但这也只是智能指针的雏形(因为它不具有指针的操作):
在这里插入图片描述

2. 智能指针的发展历程

智能指针其实在C++98中就有提出,只不过是在C++11中才被广泛认可。所以要研究好智能指针,顺着历史的发展来探索智能指针也未尝不可。

a. auto_ptr

在这里插入图片描述

auto_ptr是在C++98中提出的一种智能指针,它自然也遵循RAII。但是他有缺陷:
在这里插入图片描述
原因如下:
在这里插入图片描述
当使用赋值重载或者拷贝构造的时候,它会将资源的管理权转让,将原来的管理智能指针中的原生指针置为空,也就是对象悬空这样会导致使用者经常会出现访问越界的问题。这也是为什么C++11中智能指针才被广泛认可。
接下来我们简单实现一下auto_ptr:
在这里插入图片描述

在这里插入图片描述

b. unique_ptr

unique_ptr是C++11中提出的智能指针,它没有auto_ptr的缺点,因为它就不能将资源管理权进行转让(也就是无法使用赋值重载和拷贝构造)。
在这里插入图片描述
在这里插入图片描述

我们也可以试着自己实现一个简单的:
要实现对应的特性,我们可以只声明并且设为私有。
在这里插入图片描述
在这里插入图片描述
还有一种就是delete掉赋值重载和拷贝构造:

在这里插入图片描述

在这里插入图片描述
当然它也可以正常使用:
在这里插入图片描述

它的缺点也显而易见,就是同一处资源只能一个对象管理,所以就又有了shared_ptr。

c. shared_ptr

在这里插入图片描述
它的特点就是可以有多个shared_ptr对象共同管理同一处资源:
在这里插入图片描述
我们也可以自己实现,那么在实现的时候要实现多个对象共同管理一份资源,那就得使用引用计数了,但是这个引用计数的存储位置也必须是堆上开辟出来的,假如是成员变量的话就无法实现同一块资源有多少个shared_ptr对象管理了。假如是静态变量的话,如果程序中有两处资源需要shared_ptr管理也无法实现。
要注意:

计数只有在拷贝构造和赋值重载时才++。
析构时要根据引用计数来判断否真的释放资源。

实现如下:
在这里插入图片描述
在这里插入图片描述
它也有缺点:
在这里插入图片描述
在这里插入图片描述
可以看到这样设置节点是不正确的导致节点无法连接,所以应该是这样:
在这里插入图片描述
这样就会正常(这里多次释放不报错的原因是因为delete对空指针做了特殊处理):
在这里插入图片描述
但是这样就会出问题:
在这里插入图片描述
库中的也会出现这种问题:
在这里插入图片描述
在这里插入图片描述

这其中的逻辑如下:
在这里插入图片描述

就会导一直循环要释放从而无法释放资源。这种现象叫做循环引用。为了解决这种现象就又出现了weak_ptr。

weak_ptr

weak_ptr可以说是专门为了shared_ptr打辅助的,而它也不遵循RAII了。它其中提供了shared_ptr的构造函数,所以我们再来简单实现一手:
在这里插入图片描述
它没有析构函数,没有对资源进行管控,也就不遵循RAII,其中的get是获取shared_ptr的原生指针。
在这里插入图片描述
在这里插入图片描述
循环引用问题能够解决的原理是:使用weak_ptr之后没有增加两节点资源的引用计数,从而在析构时,能够很自然的释放资源

3. 定制删除器

在上面讲述中我们只是,delete了一块资源,那要是一块连续的资源呢?我们就需要使用delete[]来释放资源,那如何分别,究竟释放的是一块单一资源,还是一块连续的资源呢?C++把这个问题交给了程序员,所以就有了定制删除器,我们以unique_ptr举个例子:
在这里插入图片描述
这其中我们使用了可调用对象,包装器,模板来实现删除器的功能。

在这里插入图片描述
可以看到,不仅堆中的空间算资源,打开的文件也是资源,所以资源说的是很广泛的。

4. 总结

现在我们再回想一遍什么是RAII、智能指针?他们之间有什么关系?:

RAII它是一种思想,它其实就是利用了对象的生命周期的特点从而对资源达到控制。
而C++中的智能指针,它是RAII的一种体现,利用处于该栈帧中自定义类的析构函数
在栈帧结束时自动调用的特性,从而实现对资源的管控

而我们作为C++程序员,是必须要把内存泄漏这件事情看的非常非常非常重要的一件事:

1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。
ps:这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。
需要下一条智能指针来管理才有保证。
2. 采用RAII思想或者智能指针来管理资源。
3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功
 能选项。
4 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。

相关推荐

  1. Pytorch安装小坑(Windows+cu111

    2023-12-22 17:22:01       11 阅读
  2. <span style='color:red;'>CI</span>/<span style='color:red;'>CD</span>

    CI/CD

    2023-12-22 17:22:01      32 阅读
  3. CCS 2023

    2023-12-22 17:22:01       18 阅读
  4. VGG16-CF-VGG11实验报告

    2023-12-22 17:22:01       23 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-22 17:22:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-22 17:22:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-22 17:22:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-22 17:22:01       18 阅读

热门阅读

  1. SQL server 数据库 sql常用语句

    2023-12-22 17:22:01       44 阅读
  2. 基于SpringBoot的体育馆使用预约管理系统

    2023-12-22 17:22:01       49 阅读
  3. Zookeeper 集群搭建过程中常见错误

    2023-12-22 17:22:01       26 阅读
  4. DeamonSet详解

    2023-12-22 17:22:01       31 阅读
  5. vue介绍以及基本指令

    2023-12-22 17:22:01       30 阅读
  6. LeetCode239. Sliding Window Maximum

    2023-12-22 17:22:01       33 阅读
  7. Macos 删除过期失效的软链接symlink

    2023-12-22 17:22:01       43 阅读
  8. 【PHP】取出数组中的第一个元素

    2023-12-22 17:22:01       41 阅读
  9. 常见数据库安装

    2023-12-22 17:22:01       33 阅读