浅析智能指针

为什么要有智能指针?

1.什么是智能指针?

  智能指针是一个类,这个类的构造函数中传入一个普通指针,析构函数中释放传入的指针。智能指针的类都是栈上的对象,所以当函数(或程序)结束时会自动被释放。

2.为什么需要智能指针?

  指针在C++的学习和使用中是必不可少的,重要性可想而知,如果对指针的理解不是很深入,很容易产生野指针,造成内存泄漏等问题。这时有人就会想到用一个“有思想”的指针,知道自己什么时候该释放,问题不就解决了吗。智能指针正好是针对这些问题所存在的,因为它是存放在栈上的模板对象,在栈内部包了一层指针。栈的生命周期结束时,它里面的指针自然也就释放了。这样一个“有思想”的指针就实现了。

3.智能指针和普通指针的区别在哪里?

  智能指针实际是利用RAll(资源获取及初始化)的技术对普通指针加了一层封装机制,目的是为了使智能指针可以方便的管理一个对象的生命期。如果是普通指针,使用这个对象之后我们需要删除它。如果忘记删除,会造成一个野指针、内存泄漏等问题,在调用运行这个函数的时候就会抛出异常。

智能指针的实现。

1.基于RAII思想的SmartPtr类

  RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源的简单技术,是C++语言的一种管理资源、避免泄漏的惯用法。
这种思想是在对象构造的时候获取资源,然后控制对资源的访问,使之在对象生命周期始终保持有效,最有在对象析构的时候释放资源。这种做法不需要显式地释放资源并且对象所需要的资源在其生命周期内始终保持有效。

template<class T>
class SmartPtr{
public:SmartPtr(T* ptr = nullptr) :_ptr(ptr){}~SmartPtr(){if (_ptr)delete _ptr;}//SmartPtr写到这里还不能算是一个智能指针,这个指针现在是符合了RAII机制,//但是还不具有指针的行为,需要将*和->重载才可以T& operator*(){return *_ptr;}T& operator->(){return _ptr}
};
2.auto_ptr

  在C++98中就提出了智能指针auto_ptr
  auto_ptr的实现原理:管理权转移的思想。
  接下来通过简单地模拟实现auto_ptr来了解它的原理(命名为Auto_Ptr)

template<class T>
class Auto_Ptr
{
public:AutoPtr(T* ptr = nullptr) :_ptr(ptr){}~AutoPtr(){if (_ptr)delete _ptr;}//一旦发生了拷贝,就将sp中的资源转移到当前对象中,然后sp与它所管理的资源断开练习//这样就解决了一块空间被多个对象使用造成的程序崩溃问题。AutoPtr(AutoPtr<T>& sp){//检查是不是自己给自己赋值if (this != &sp){//释放当前对象中的资源if (_ptr)delete _ptr;//转移sp中资源到当前对象_ptr = sp._ptr;sp._ptr = nullptr;}return *this;}private:T* _ptr;
};

auto_ptr存在的问题:
  当对象拷贝或者赋值后,前面的对象就悬空了,再使用前面对象访问资源就会出现问题
   C++98中设计的auto_ptr问题是非常明显的,所以在实际工作中很多公司直接明确规定了不能使用auto_ptr这个智能指针,已被C++11明确声明不再支持使用。

3. unique_ptr

   C++11中开始提供更靠谱的智能指针unique_ptr
   unique的实现原理:防止被拷贝
   接下来通过简单地模拟实现auto_ptr来了解它的原理(命名为Unique_Ptr)

template<class T>
class Unique_Ptr
{
public:Unique_Ptr(T* ptr = nullptr) : _ptr(ptr){}~Unique_Ptr(){if (_ptr)delete _ptr;}Unique_Ptr& operator*(){return *_ptr;}Unique_Ptr& operator->(){return _ptr;}
private:Unique_Ptr(Unique_Ptr<T> const &);Unique_Ptr operator=(Unique_Ptr<T> const &);//上述方法是C++98中给出的防止被使用方法:只声明不实现,并将其生命为私有//下面是C++11中给出的防止被使用的方法:=delete;Unique_Ptr(Unique_Ptr<T> const &)=delete;Unique_Ptr operator=(Unique_Ptr<T> const &)=delete;T* _ptr;
};
4.shared_ptr

  基于前面智能指针不能拷贝的缺陷,C++11提供了更为可靠并且可以拷贝的shared_ptr
shared_ptr的实现原理是通过引用计数的方式来实现多个shared_prt对象之间共享资源,这就和一个宿舍都要去上课,每个人走的时候都会通知让最后一个走的把门锁了。
shared_prt在内部给每个资源都维护者一份计数,用来记录这份资源被多少个对象所共享。在对象调用析构函数的时候,说明这个对象不在使用这份资源了,他的引用计数要减一。如果他是最后一个使用者(引用计数减一后为零),他就得释放这块资源。如果不是最后一个使用者(引用计数减一后不为零),就不能释放这块资源。
  接下来通过简单地模拟实现auto_ptr来了解它的原理(命名为Shared_Ptr)

#include <thread>
#include <mutex>template<class T>
class Shared_Ptr
{
public:Shread_Ptr(T* ptr = nullptr): _ptr(ptr), _pCount(new int(1)), _pMutex(new mutex){if (_ptr == nullptr)*_ptrCount = 0;}~Shread_Ptr(){Release();}//拷贝构造函数Shared_Ptr(Shared_Ptr<T>& sp):_ptr(sp._ptr), _pCount(sp._pCount), _pMutex(sp._pMutex){if (_ptr)		//如果不是空指针,增加引用计数AddCount();}//重载=运算符Shared_Ptr<T>& operator=(const Shared_Ptr<T>& sp){if (_prt != sp._ptr)	//检查是不是自己给自己赋值{Release();			//释放所管理的旧资源_ptr = sp._ptr;_pCount = sp._pCount;_pMutex = sp._pMutex;if (_ptr)		//如果不是空指针,增加引用计数AddCount();}return *this;}Shared_Ptr<T>& operator*(){return *_ptr;}Shread_Ptr<T>& operator->(){return _ptr;}T* Get(){return _ptr;}
private://加减引用计数使用锁对操作进行加锁或者使用原子操作int AddCount(){_pMutex->lock();++(*_pCount);_pMutex->unlock();return *_pCount;}int SubCount(){_pMutex->lock();--(*_pCount);_pMutex->unlock();return *_pCount;}void Release(){//如果指向的指针不为空,并且这个对象是最后一个使用这个指针的人,开始释放这份资源if (_ptr && 0 == SubCount()){delete _ptr;delete _pCount;}}private:T* _ptr;			//指向管理资源的指针int *_pCount;		//引用计数mutex* _pMutex;		//互斥锁
};
4.1 shared_ptr的线程安全问题。

  假设在上面代码中对引用计数进行加减时没有加锁或者进行原子操作,由于智能指针对象中引用计数是多个智能指针对象共享的,两个线程中智能指针的引用计数同时进行加或减操作时,这
个操作不是原子的,引用计数原来是1,加了两次,可能还是2。这样引用计数就错乱了,会导致资源没有按照约定释放或者程序崩溃的问题。所以智能指针中对引用计数的加减操作是必须要要加锁的,也就是说引用计数的操作是线程安全的。

4.2 shared_ptr的循环引用问题。

先实现一个循环引用的场景:

#include <memory>
#include <iostream>using namespace std;struct ListNode
{int _data;shared_ptr<ListNode> _prev;shared_ptr<ListNode> _next;~ListNode(){cout << "~ListNode()" << endl;}
};int main()
{shared_ptr<ListNode> node1(new ListNode);shared_ptr<ListNode> node2(new ListNode);//打印这两个节点的引用计数cout << node1.use_count() << endl;cout << node2.use_count() << endl;node1->_next = node2;node2->_prev = node1;//打印这两个节点的引用计数cout << node1.use_count() << endl;cout << node2.use_count() << endl;return 0;
}

打印结果如下:
在这里插入图片描述
很明显,没有调用析构函数,画图解析:
在这里插入图片描述

分析:

  1. <>a.node1和node2两个智能指针对象指向两个节点,引用计数变为1。
  2. node1的_next指向node2,node2的_prev指向node1,引用计数变为2。
  3. 当两个智能指针释放空间时,引用计数减到1,但是_next还指向着下一个节点,_prev还指向着上一个节点。
  4. 也就是说,如果想释放node1中的_next,就先得释放它指向的node2,但是如果想释放node2就得将node2的_next和_prev先释放,而_prev指向了node1,得先将node1释放了才能释放_prev。这样一来,如果想释放node1就得先释放node2,要释放node2就得先释放node1。这样就构成了循环引用,谁也不会释放 针对这一问题,解决方案是在引用计数的场景下,把节点中的_prev和_next换成weak_ptr就可以了。
  5. 其中的原理是:当node1->_next= node2;和node2->_prev = node1时,weak_ptr的_next和_prev不会增加 node1和node2的引用计数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/494961.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论强化学习的根本缺陷

来源&#xff1a;AI 科技评论摘要&#xff1a;本文来自斯坦福大学博士生 Andrey Kurenkov 在 The Gradient 上发表的文章。在本文中&#xff0c;我们将讨论人工智能的一个核心领域——强化学习——的局限性。在这个过程中&#xff0c;起初我们将通过一个有趣的例子提出我们要讨…

最后期限已至,高通收购恩智浦全剧终!中国一刀切断高通物联网全局梦!

来源&#xff1a;物联网智库摘要&#xff1a;没有一种商业模式可以永享特权。物联网时代&#xff0c;当专利和芯片两大支柱业务均受到剧烈冲击和威胁之下&#xff0c;如何创新以自救&#xff0c;正是考验高通全面战略能力的关键时刻&#xff0c;恩智浦是当前高通给出的最好答案…

斯坦福证明神经网络能直接在光学芯片上训练

来源&#xff1a;全球人工智能摘要&#xff1a;据报道&#xff0c;美国斯坦福大学的研究人员已经证明&#xff0c;可以直接在光学芯片上训练人工神经网络。据报道&#xff0c;美国斯坦福大学的研究人员已经证明&#xff0c;可以直接在光学芯片上训练人工神经网络。这一重大突破…

用Keil-MDK开发TQ2440裸机程序入门教程——LED流水灯实现

觉得此编文章很详实&#xff0c;故转载之&#xff0c;来自http://www.amobbs.com/thread-5281512-1-1.html 开发板也差不多买了半年了, 以前照着教程用的是软件是ADS,在win7下老是崩溃, 后来才知道ADS早就不提供支持了, ADS的公司怎样怎样了...(此处省略300..) 然后我就捣鼓着怎…

关于量子计算,你应该知道的七个事实

来源&#xff1a;资本实验室摘要&#xff1a;在很多人眼中&#xff0c;量子计算机被认为能够完成经典计算机所不能完成的任务。聚焦前沿科技创新与传统产业升级在很多人眼中&#xff0c;量子计算机被认为能够完成经典计算机所不能完成的任务。事实上&#xff0c;如果量子计算机…

机器学习帮助人类找到最硬的过渡金属氮化物

来源&#xff1a;中国科学杂志社摘要&#xff1a;南京大学物理学院孙建教授和王慧田教授领导的研究团队发展了机器学习加速晶体结构搜索的方法&#xff0c;并用其预测了一种超硬的钨氮化合物。机器学习算法在很多领域取得了令人瞩目的进步&#xff0c;从而广受人们关注&#xf…

WEB攻防实战篇,思维导图

转载于:https://www.cnblogs.com/sin4/archive/2012/06/16/2551603.html

二维数组按行和按列遍历的效率

按行遍历的效率大概是是按列遍历的0.5倍 在c语言中&#xff0c;数组在内存中是按行存储的&#xff0c;按行遍历时可以由指向数组第一个数的指针一直向后遍历&#xff0c;由于二维数组的内存地址是连续的&#xff0c;当前行的尾与下一行的头相邻&#xff0c;所以可以直接到下一行…

解读《自适应机器人交互白皮书》:机器人交互需要突破性技术

来源&#xff1a;机器人创新生态摘要&#xff1a;7月11日雷克大会&#xff0c;英特尔中国研究院机器人交互实验室研发总监任海兵在演讲时&#xff0c;就白皮书中的内容进行了重点解读。个人服务机器人在近年来随着人工智能的快速发展开始得到不少关注。个人服务机器人是否真正能…

最长升序子串1231

题目与解析 给定n个数字&#xff0c;在这n个数字中找出最长上升子序列。 那么什么是上升子序列呢&#xff1f; 上升子序列就是在一个数列中递增的部分&#xff0c;不一定是连续的&#xff0c;比如说 图中的24678和24679都是数列24635798的上升子序列 解题思路 就按图上2 4 …

科学革命与科学教科书

来源&#xff1a;《出版科学》2018年第4期摘要&#xff1a;借助科学哲学的反思&#xff0c;加上科学家和出版人的创新实践&#xff0c;一定能够出现既能促进常规科学研究、又能为科学革命做出某些准备的新型科学教科书。《科学革命的结构》托马斯 • 库恩著&#xff0c;金吾伦、…

物联网可应用于十大行业嘛?

来源&#xff1a;亿欧智库摘要&#xff1a;近些年来&#xff0c;全球经济增长乏力&#xff0c;物联网已变成了各国经济发展的新动力。基于此&#xff0c;亿欧智库近日将发布一份新的报告《2018物联网行业应用研究报告》&#xff0c;报告总结出了物联网的十大应用行业&#xff0…

浅析死锁

什么是死锁&#xff1f; 死锁就是两个或多个进程在执行的过程中&#xff0c;由于竞争资源或者由于彼此通信而造成的一种阻塞现象&#xff0c;当进程处于这种状态时&#xff0c;如果没有外力的作用&#xff0c;这些进程都无法继续向前进行。这是操作系统层面的一个错误&#xff…

2018年全球AI突破性技术TOP10

来源&#xff1a;艾瑞网摘要&#xff1a;聪明的科技公司都不再单一的专注于自己的传统业务&#xff0c;而是着眼于未来&#xff0c;不断创新技术&#xff0c;跨界融合打造一个整合的生态系统。人工智能是个高科技、宽领域、多维度、跨学科的集大成者&#xff0c;从立足大数据、…

全球11个行业、71家知名企业的创新Lab与布局

来源&#xff1a;CBInsights新技术的革新引发了商业世界重构的浪潮&#xff0c;在这一波由人工智能引领的创新潮流里唯有拥抱变化才能不为时代淘汰&#xff0c;顺应趋势取得更大的发展。新技术的革新引发了商业世界重构的浪潮&#xff0c;在这一波由人工智能引领的创新潮流里唯…

组队竞赛

题目解析&#xff1a; 队伍的水平值等于该队伍队员中第二高水平值&#xff0c;为了所有队伍的水平值总和最大的解法&#xff0c;也就是说每个队伍的第二个值是尽可能大的值。所以实际值把最大值放到最右边&#xff0c;最小是放到最左边。 解题思路&#xff1a; 本题的主要思路是…

【SD】差异值 生成 同一人物 制作 表情包 【1】

说明&#xff1a;只对AI生成的人物&#xff0c;效果稳定。 Reference差异值 生成表情 首先生成一张图片。 测试命令&#xff1a;1 man,chibi,full body, 模型&#xff1a;envyclarityxl02_v10.safetensors [f6c13197db] 种子&#xff1a;2704867166 》》测试命令&#xff1a…

MySQL索引原理、失效情况

声明&#xff1a;本文是小编在学习过程中&#xff0c;东拼西凑整理&#xff0c;如有雷同&#xff0c;纯属借鉴。 Mysql5.7的版本, InnoDB引擎 目录 1 mysql索引知识 1.1 BTree索引 1.2 主键索引和普通索引的区别 1.3 唯一索引vs普通索引 2 mysql索引优化 2.1 查看索引使…

2018年人工智能全景图与发展趋势分析

来源&#xff1a;专知摘要&#xff1a;风险资本家马特图尔克&#xff08;Matt Turck&#xff09;最近发布文章&#xff0c;能力越大&#xff0c;责任越大&#xff0c;介绍了大数据与人工智能在2018年发展的趋势&#xff0c;并发布了全景图&#xff0c;涵盖基础架构、开源框架、…

李晨 | 无人机市场浅析

来源&#xff1a;无人机作者简介&#xff1a;西北工业大学民用无人机研发中心副主任无人机市场浅析无人机市场分类过去无人机一直是军用为主&#xff0c;不论是伊拉克战争还是好莱坞大片&#xff0c;无人机在执行军事任务方面起到了不可替代的作用。在2010年以前&#xff0c;军…