【C++】详细版 RAII技术的应用之智能指针(智能指针发展历程和简单模拟实现介绍)

本文主要是介绍【C++】详细版 RAII技术的应用之智能指针(智能指针发展历程和简单模拟实现介绍),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

目录

 

前言

一、智能指针有什么用?

二、什么是RAII(智能指针的底层思想)?

       三、智能指针的发展历程以及模拟实现

1.auto_ptr(C++98)

2.unique_ptr(C++11)

3.shared_ptr(C++11)


前言

C++中的智能指针是一种管理内存的工具,它可以自动地跟踪和管理所指向的内存块。智能指针通常用于替代手动管理内存的机制,避免内存泄漏和野指针等问题。


一、智能指针有什么用?

下面我们来看一种场景:

#include <iostream>
using namespace std;
double Division(int x, double y)
{cin >> x >> y;if (0 == y)throw invalid_argument("除数为0无法计算");return x / y;
}
void func()
{pair<int, string>* p1 = new pair<int, string>(7, "CSDN");int x;double y;cin >> x >> y;cout << Division(x, y) << endl;delete p1;p1 = nullptr;
}
int main()
{try{func();}catch (exception& e){cout << e.what() << endl;}return 0;
}

从上面代码可以分析出:如果Dvision函数中抛异常的话,那么p1指向的空间内存就无法释放,造成内存泄露。因此此时就需要一个智能指针对p1指向的空间内存进行自动释放。因此我们可以这样做:利用对象的生命周期来控制手动开辟的内存资源。下面我们来简单实现一下着种方法:

#include <iostream>
using namespace std;
class A
{
public:A(pair<int, string>* ptr):_ptr(ptr){}~A(){cout << "delete" << endl;}
private:pair<int, std:string>* _ptr;
};
double Division(int x, double y)
{cin >> x >> y;if (0 == y)throw invalid_argument("除数为0无法计算");return x / y;
}
void func()
{pair<int, string>* p1 = new pair<int, string>(7, "CSDN");A a(p1);int x;double y;cin >> x >> y;cout << Division(x, y) << endl;delete p1;p1 = nullptr;
}
int main()
{try{func();}catch (exception& e){cout << e.what() << endl;}return 0;
}

1.当Division函数中不抛异常的情况,代码运行结果如下:

0928870634c94246a8fe5975d815164a.png

2.当Division函数中抛异常的情况,代码运行结果如下:

6c932c81f1c245088e28e582341fdc7c.png

 由此可见,将p1指向的资源托管给对象a控制是利于其资源释放的,p1指向的资源会随着对象a的销毁而销毁。

二、什么是RAII(智能指针的底层思想)?

智能指针是RAII技术的应用。

RAII(Resource Acquisition Is Initialization)是一种 利用对象生命周期来控制程序资源(如内
存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效, 最后在
对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做
法有两大好处:
first:不需要显式地释放资源。
second:采用这种方式,对象所需的资源在其生命期内始终保持有效。

三、智能指针的发展历程以及模拟实现

智能指针的大体是有三个阶段的发展:第一阶段C++98的auto_ptr;第二阶段C++11的unique_ptr;第三阶段C++11中的shared_ptr。通过不断创新与努力C++11最终发布了shared_ptr,这也是智能指针的最终版本,是最优的。

我们分别来模拟实现一下这几种智能指针,以及对它们做出分析。

在此之前我们必须要明白其实智能指针是一个类对象,该类封装了所需要管理的资源,以及内部实现了具有指针功能的运算符重载成员函数(operator*  operator->)。

1.auto_ptr(C++98)

auto_ptr 的实现原理:管理权转移的思想,下面简化模拟实现了一份 keke::auto_ptr 来了解它的原
#include <iostream>
using namespace std;
namespace keke
{template<class T >class auto_ptr{public:auto_ptr(T* ptr):_ptr(ptr){}auto_ptr(auto_ptr& ap):_ptr(ap._ptr){//资源管理权转移ap._ptr = nullptr;}auto_ptr<T>& operator=(auto_ptr& ap){//检查是否为自己给自己赋值,如果是的话那么不进行赋值if (_ptr != ap._ptr){//释放被赋值对象里的资源if (_ptr)delete _ptr;//将对象ap的资源转移给被赋值对象_ptr = ap._ptr;ap._ptr = nullptr;}return *this;}~auto_ptr(){if (_ptr)delete _ptr;}//要像指针一样使用T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};
}
int main()
{keke::auto_ptr<int> ap1(new int(5));keke::auto_ptr<int> ap2(ap1);++(*ap1);//由于ap1将资源权限转移给了ap2,则ap1_ptr==nullptr//导致读取数据错误!++(*ap2);return 0;
}

b3b48b5b8afd4d61b54b385e2a675c56.png

基于上面的问题,auto_ptr是不建议被使用的。

2.unique_ptr(C++11)

unique_ptr的实现原理: 简单粗暴的防拷贝,下面简化模拟实现了一份UniquePtr 来了解它的原

unique_ptr是在auto_ptr的基础上改进的。只是将auto_ptr模拟实现中的拷贝构造函数和赋值运算符重载访问权限改为private,或者是在两个默认成员函数后加=delete。

template<class T >class unique_ptr{public:unique_ptr(T* ptr):_ptr(ptr){}unique_ptr(unique_ptr& up) = delete;unique_ptr<T>& operator=(unique_ptr& up) = delete;~unique_ptr(){if (_ptr)delete _ptr;}//要像指针一样使用T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};

智能指针unique_ptr对于不需要拷贝的场景适用,但是需要拷贝的场景则不能使用。

3.shared_ptr

C++11 中开始提供更靠谱的并且支持拷贝的 shared_ptr。
shared_ptr 的原理: 是通过引用计数的方式来实现多个shared_ptr对象之间共享资源
举一个例子:放学后最后一个走出教室的同学需要把教室的门上锁。
1. shared_ptr在其内部, 给每个资源都维护了着一份计数,用来记录该份资源被几个对象共
2. 在 对象被销毁时 ( 也就是析构函数调用 ),就说明自己不使用该资源了,对象的引用计数减
一。
3. 如果引用计数是 0,就说明自己是最后一个使用该资源的对象, 必须释放该资源
4. 如果不是 0,就说明除了自己还有其他对象在使用该份资源, 不能释放该资源,否则其他对
象就成野指针了。
#include <iostream>
using namespace std;
namespace keke
{template<class T >class shared_ptr{public:shared_ptr(T* ptr = nullptr):_ptr(ptr),_pCount(new int(1)){}shared_ptr(shared_ptr& sp):_ptr(sp._ptr),_pCount(sp._pCount){++(*_pCount);}shared_ptr<T>& operator=(shared_ptr& sp){if (_ptr != sp._ptr)//检查是否为自己给自己赋值Release();_ptr = sp._ptr;_pCount = sp._pCount;++(*_pCount);return *this;}void Release(){if (0 == --(*_pCount) && _ptr){cout << "delete" << endl;delete _ptr;delete _pCount;}}~shared_ptr(){Release();}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}int use_count(){return *_pCount;}private:T* _ptr;int* _pCount;};
}
int main()
{keke::shared_ptr<string> sp1(new string("CSDN"));keke::shared_ptr<string> sp2 = sp1;keke::shared_ptr<string> sp3(sp1);keke::shared_ptr<pair<int, string>> sp4(new pair<int, string>(5, "CSDN"));keke::shared_ptr<pair<int, string>> sp5(sp4);return 0;
}
运行结果如下:
39d14850788344428b9c4db955af0722.png

 shared_ptr智能指针采用计数,让最后一个释放的对象释放资源,虽然复杂一下,但是非常完美!shared_ptr也是目前主要使用的智能指针。

 

 

这篇关于【C++】详细版 RAII技术的应用之智能指针(智能指针发展历程和简单模拟实现介绍)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/977963

相关文章

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

Python脚本实现自动删除C盘临时文件夹

《Python脚本实现自动删除C盘临时文件夹》在日常使用电脑的过程中,临时文件夹往往会积累大量的无用数据,占用宝贵的磁盘空间,下面我们就来看看Python如何通过脚本实现自动删除C盘临时文件夹吧... 目录一、准备工作二、python脚本编写三、脚本解析四、运行脚本五、案例演示六、注意事项七、总结在日常使用

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Python进阶之Excel基本操作介绍

《Python进阶之Excel基本操作介绍》在现实中,很多工作都需要与数据打交道,Excel作为常用的数据处理工具,一直备受人们的青睐,本文主要为大家介绍了一些Python中Excel的基本操作,希望... 目录概述写入使用 xlwt使用 XlsxWriter读取修改概述在现实中,很多工作都需要与数据打交

使用Python实现在Word中添加或删除超链接

《使用Python实现在Word中添加或删除超链接》在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能,本文将为大家介绍一下Python如何实现在Word中添加或... 在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能。通过添加超

windos server2022里的DFS配置的实现

《windosserver2022里的DFS配置的实现》DFS是WindowsServer操作系统提供的一种功能,用于在多台服务器上集中管理共享文件夹和文件的分布式存储解决方案,本文就来介绍一下wi... 目录什么是DFS?优势:应用场景:DFS配置步骤什么是DFS?DFS指的是分布式文件系统(Distr

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭