当前位置: 首页 > news >正文

宿迁住房和城乡建设网站公司网站建设 毕业设计

宿迁住房和城乡建设网站,公司网站建设 毕业设计,不懂技术与产品怎样做网站,入门网站建设#x1f496;作者#xff1a;小树苗渴望变成参天大树#x1f388; #x1f389;作者宣言#xff1a;认真写好每一篇博客#x1f4a4; #x1f38a;作者gitee:gitee✨ #x1f49e;作者专栏#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法#x1f384; 如 果 你 … 作者小树苗渴望变成参天大树 作者宣言认真写好每一篇博客 作者gitee:gitee✨ 作者专栏C语言,数据结构初阶,Linux,C 动态规划算法 如 果 你 喜 欢 作 者 的 文 章 就 给 作 者 点 点 关 注 吧 文章目录 前言一、为什么设计出智能指针二、智能指针的使用及原理2.1 最简单的智能指针 三、智能指针的发展史3.1 auto_ptr3.2 unique_ptr3.3 shared_ptr3.4 weak_ptr(循环引用)3.5定制删除器 四、总结 前言 今天我们来讲解一个好理解有好用的知识点–智能指针。智能指针有很多种但是每种都有相同之处一会按顺序介绍的哦都是每一种的补充他的作用是解决没有办法再回头来释放的空间导致会内存泄漏所以需要指针指针来解决这个问题话不多说我们开始进入正文讲解 一、为什么设计出智能指针 再以前是没有智能指针的东西那为什么现在设计出来了看代码 void f() {pairstring, string* p1 new pairstring, string;//可能会出现错误抛异常fun();delete p1; } int main() {f();return 0; }以前我们申请空间就释放空间中间有啥都无所谓,肯定没有问题的但是异常出来之后就会导致fun出现异常这时候就会影响执行流可能会释放不到p1,这样就导致内存泄漏 **那我们的java有没有智能指针呢**答案是没有的他有垃圾回收器可以自动回收内存那C为什么不搞呢原因就是c程序是直接跑在os上的而Java先再虚拟机上跑而虚拟机再os上跑多了一层所以C想要直接去搞垃圾回收器是一件很耗成本的事有便宜就有付出所以再一些追求性能的程序大部分都选择C比如游戏遥控器需要及时响应的。并且C程序和os是直接互通的 有了异常来说我们来看下面的代码 1 int div() {int a, b;cin a b;if (b 0)throw invalid_argument(除0错误);return a / b; } void f() {pairstring, string* p1 new pairstring, string;//可能会出现错误抛异常try{div();//正常执行逻辑}catch (...)//接收任意类型的异常{cout delete: p1 endl;delete p1;//先释放throw;//抛出去} } int main() {try{f();}catch (const exception e)//捕获抛出来的异常{cout e.what() endl;}return 0; }大家仔细看我们的f函数里面有一块动态申请的空间如果div里面抛异常的我们再抛出去之前就给释放就可以解决问题。也是可以解决问题的。 这就是由于异常那个出现导致执行流的变化。 2将上面的f()函数改成下面这样看看其余不变。 void f() {pairstring, string* p1 new pairstring, string;//可能会出现错误抛异常pairstring, string* p2 new pairstring, string;try{div();//正常执行逻辑}catch (...)//接收任意类型的异常{cout delete: p1 endl;delete p1;//先释放throw;//抛出去}cout delete: p1 endl;delete p1;cout delete: p2 endl;delete p2; }我给大家来分析一下再申请的时候也可能出现申请失败概率很小但有可能此时p1申请失败那下面的代码就不会执行退出函数也不存申请内存释放问题万一p1申请成功执行申请p2的时候出现了异常退出了函数那么刚申请的p1就没有办法释放有人说给p2也加一个异常处理 void f() { pairstring, string* p1 new pairstring, string;//可能会出现错误抛异常 pairstring, string* p2 new pairstring, string;//可能会出现错误抛异常 try//是p2的异常捕获 {;//正常执行逻辑 } catch (...)//接收任意类型的异常 {cout delete: p1 endl;delete p1;//先释放throw;//抛出去 } try//是div的异常捕获 {div();//正常执行逻辑 } catch (...)//接收任意类型的异常 {cout delete: p1 endl;delete p1;//先释放throw;//抛出去 } cout delete: p1 endl; delete p1; cout delete: p2 endl; delete p2; }上面代码可以解决我说的场景但是出现下面的场景呢 内存泄漏的危害长期运行的程序出现内存泄漏影响很大如操作系统、后台服务等等出现 内存泄漏会导致响应越来越慢最终卡死 所以针对可能造成内存泄漏的空间我们不可能每一个都要捕获一下异常所以针对这个问题我们要想办法解决这才引入了智能指针 二、智能指针的使用及原理 相信通过上面的例子大家应该明白C11要搞出智能指针了吧接下来我将带大家来学习智能指针。 2.1 最简单的智能指针 在对象构造时获取资源接着控制对资源的访问使之在对象的生命周期内始终保持有效最后在 对象析构的时候释放资源。借此我们实际上把管理一份资源的责任托管给了一个对象。这种做 法有两大好处 不需要显式地释放资源。 采用这种方式对象所需的资源在其生命期内始终保持有效 我们抛出异常就意味结束了此函数想要解决释放将指针写成一个类自动调用析构函数就可以了来看代码 class smartptr{public:smartptr(pairstring, string* sp):_ptr(sp){}~smartptr(){cout delete: _ptr endl;delete _ptr;}private:pairstring, string* _ptr;};这是一个最简单的智能指针函数不管啥时候结束都会自动调用析构函数进行释放的我们来看结果 为了能适应任何类型我们将智能指针设计成模板的形式 templateclass Tclass smartptr{public:smartptr(T* sp):_ptr(sp){}~smartptr(){cout delete: _ptr endl;delete _ptr;}private:T* _ptr;}; xdh::smartptrpairstring, string p1 new pairstring,string; xdh::smartptrpairstring, string p2 new pairstring, string;难道智能指针这样就可以了 我们要达到像普通指针一样完成下面的操作 所以我们要实现*和-,这个再迭代器那一块已经孰能生巧了再类里面去实现那一下就好了 T operator*() {return *_ptr; } T* operator-() {return _ptr; }完美的解决了我们的问题。 按照正常情况我们的智能指针的内容讲解的差不多了但是我们不能学到这里就结束了这只是自己造轮子简单的实现了我们还要学习库里面给我们提供的智能指针这就要来讲讲智能指针的发展史了 三、智能指针的发展史 C 98 中产生了第一个智能指针auto_ptr.C boost给出了更实用的scoped_ptr和shared_ptr和weak_ptr.C TR1引入了shared_ptr等。不过注意的是TR1并不是标准版。C 11引入了unique_ptr和shared_ptr和weak_ptr。需要注意的是unique_ptr对应boost 的scoped_ptr。并且这些智能指针的实现原理是参考boost中的实现的。 我们会介绍四款智能指针auto_ptr,unique_ptr,shared_ptr,weak_ptr,这四个我都会带大家去使用以及模拟实现一下让大家更好的理解智能指针。 我们上面一开始自己实现的智能指针还有一些问题解决不了那就是下面的场景 int main() {xdh::smartptrstring sp1(new string(xxxxx));xdh::smartptrstring sp2(new string(yyyyy));sp1 sp2;return 0; }所以我们才要讲解上面四个智能指针。 3.1 auto_ptr 我们的第一款智能指针是C98搞出来叫auto_ptr但是这个太坑了也会大部分公司禁止使用的为什么会这么说他呢他有悬空 我们来使用一下看看 void f() {auto_ptrstring p1(new string(111));auto_ptrstring p2(p1);auto_ptrstring p3(new string(111));auto_ptrstring p4(new string(111));p4 p3; }我们的auto_ptr再实现拷贝和赋值的时候就会使得被拷贝的对象发生悬空如果再对被拷贝对象操作就会出现问题不使用就没事。但是这种再开发中就不被允许万一再前面使用了被拷贝对象后面悬空了想看看值就会出现问题他的实现原理很见到就是把资源给别人把自己置空就可以了。 auto_ptr的实现原理管理权转移的思想下面简化模拟实现了一份xdh::auto_ptr来了解它的原 理 templateclass Tclass auto_ptr{public:auto_ptr(T* ptr):_ptr(ptr){}auto_ptr(auto_ptrT sp):_ptr(sp._ptr){// 管理权转移sp._ptr nullptr;}auto_ptrT operator(auto_ptrT ap){// 检测是否为自己给自己赋值if (this ! ap){// 释放当前对象中资源if (_ptr)delete _ptr;// 转移ap中资源到当前对象中_ptr ap._ptr;ap._ptr NULL;}return *this;}~auto_ptr(){if (_ptr){cout delete: _ptr endl;delete _ptr;}}// 像指针一样使用T operator*(){return *_ptr;}T* operator-(){return _ptr;}private:T* _ptr;};拷贝构造里面就很简单把指针交给新对象自己置空几乎不会自己给自己拷贝构造的再赋值里面我们就要注意自己给自己赋值就不应该置空所以加了一个判断这有点像移动构造把我的资源给你但是移动构造是将将亡值的资源给你而这里是左值我可能还要使用给你我自己就会出现问题所以这就是auto_ptr设计坑的所在之处 3.2 unique_ptr 最上面说过赋值后可能会造成析构两次的问题那么unique_ptr就是直接暴力的禁止赋值。 templateclass Tclass unique_ptr{public:unique_ptr(T* ptr):_ptr(ptr){}~unique_ptr(){cout delete: _ptr endl;delete _ptr;}T operator*(){return *_ptr;}T* operator-(){return _ptr;}//C11防拷贝deleteunique_ptr(unique_ptrT ap) delete;unique_ptrT operator(unique_ptrT ap) delete;private:T* _ptr;//C98:只声明不实现私有化unique_ptr(unique_ptrT ap);unique_ptrT operator(unique_ptrT ap);};接下来讲解的智能指针才是重点 3.3 shared_ptr 为什么会出现析构两次就会因为同一块空间有两个对象共享结束后每个对象都会自动调用自购函数进行释放所以shared_ptr采取的思想就是当一块空间只有一个指向的时候才进行释放所以需要使用一个计数来达到想要的效果 shared_ptr在其内部给每个资源都维护了着一份计数用来记录该份资源被几个对象共 享。在对象被销毁时(也就是析构函数调用)就说明自己不使用该资源了对象的引用计数减 一。如果引用计数是0就说明自己是最后一个使用该资源的对象必须释放该资源如果不是0就说明除了自己还有其他对象在使用该份资源不能释放该资源否则其他对 象就成野指针了。 库里面的使用 shared_ptrstringp1(new string(111));shared_ptrstringp2(new string(111));shared_ptrstringp3(p1);shared_ptrstringp4(new string(111));p4 p2;shared_ptrstringp5(p4); 我们使用一个静态成员作为计数行不行答案是不行的只有地址相同的对象才共享一块地址静态变量是属于类也是属于所有类对象的所以对于这两块空间都是公用一个变量的。我们要达到每块空间有自己的计数变量所以采用引用计数 templateclass Tclass shared_ptr{public:// RAII// 像指针一样shared_ptr(T* ptr nullptr):_ptr(ptr),_pcount(new int(1))//自己创建一个对象的计数初始为1{}shared_ptr(const shared_ptrT sp)//拷贝构造指向同一块空间计数:_ptr(sp._ptr),_pcount(sp._pcount){(*_pcount);}private:T* _ptr;int* _pcount;}我们来看看析构函数怎么搞的 ~shared_ptr(){if (--(*_pcount) 0)//就很自己了就可以被释放{delete _ptr;cout delete: _ptr endl;delete _pcount;}}我们来看看赋值函数怎么搞的 shared_ptrT operator(const shared_ptrT sp){if (_ptr ! sp._ptr){if (--(*_pcount) 0){delete _ptr;delete _pcount;}_ptr sp._ptr;_pcount sp._pcount;(*_pcount);}return *this;}拷贝对象可能就自己指向那块空间了被拷贝后那块空间就没人指向了所以需要判断将其释放 自己给自己赋值 p2p2;这是直接自己给自己赋值 p2p4;这是间接自己给自己赋值 都叫自己给自己赋值我们用上面自己写的来测试一下成功实现和库里面相同的效果。 shared_ptr最难的就在赋值那里面要注意判断通过第二个判断间接把自己的引用也减少一个这才是关键 3.4 weak_ptr(循环引用) 我们来看一个场景是shared_ptr解决不了的 class A { public:A(int a 0):_a(a){cout A(int a 0) endl;}~A(){cout this;cout ~A() endl;} private:int _a; };class Node { public:A _val;shared_ptrNode _next;shared_ptrNode _prev; }; void f() {shared_ptrNode p1(new Node);shared_ptrNode p2(new Node);p1-_next p2;p2-_prev p1; }我们运行程序会发现没有释放原因就是下面这幅图 造成这样的主要原因就是计数变量的增加导致结点不能释放我们的weak_ptr就是来解决这个问题的他的出现不增加计数我们来看看使用 这样就可以解决问题了。那这么一开有点类型不匹配的感觉说明weak_ptr里面肯定有使用shared_ptr的构造函数把shared_ptr的资源拿过来操作但是不做释放也不增加计数就是借此过度一下让其赋值成功间接控制没有增加计数。 我们来模拟实现一下 templateclass Tclass weak_ptr{public:// RAII// 像指针一样weak_ptr():_ptr(nullptr){}weak_ptr(const shared_ptrT sp):_ptr(sp.get()){}weak_ptrT operator(const shared_ptrT sp){_ptr sp.get();return *this;}~weak_ptr(){}T operator*(){return *_ptr;}T* operator-(){return _ptr;}private:T* _ptr;};也同样的解决我们的问题,我们再将结束打印出来看看再shared_ptr里面写一个use_count函数 int use_count(){return *_pcount;}cout sp1.use_count() endl;cout sp2.use_count() endl;sp1-_next sp2;sp2-_prev sp1;cout sp1.use_count() endl;cout sp2.use_count() endl; weak_ptr就是专门用来解决shared_ptr这个场景的没有其他作用几乎大部分场景shared_ptr就足够了 3.5定制删除器 定制删除其只针对shared_ptr去定制了因为他的使用范围最广我们来回顾一下shared_ptr的析构 ~shared_ptr(){if (--(*_pcount) 0)//就很自己了就可以被释放{delete _ptr;cout delete: _ptr endl;delete _pcount;}}我们看到这种释放就写死了只能这样去申请空间了 xdh::shared_ptrA p1(new A); 如果我想这样去申请,就会出现问题因为需要delete[]去释放。 xdh::shared_ptrA p1(new A[10]); 有了上面的问题我们才引入了定制删除器。 其实就是传一个仿函数进去了 templateclass T struct DeleteArray {void operator()(T* ptr){delete[] ptr;} };int main() {shared_ptrA sp1(new A[10], DeleteArrayA());return 0; }没使用之前是有九个都没有释放使用之后都释放了我们接下来自己来写一个定制删除器 //templateclass Tclass Dtemplateclass Tclass shared_ptr{public:// RAII // 像指针一样shared_ptr(T* ptr nullptr):_ptr(ptr), _pcount(new int(1))//自己创建一个对象的计数初始为1{}templateclass Dshared_ptr(T* ptr, D del)//这里面传进来析构函数不能使用这不是类的模板参数当然也可以直接再类外面弄一个模板参数: _ptr(ptr), _pcount(new int(1))//自己创建一个对象的计数初始为1,_del(del){}shared_ptr(const shared_ptrT sp)//拷贝构造指向同一块空间计数:_ptr(sp._ptr), _pcount(sp._pcount){(*_pcount);}shared_ptrT operator(const shared_ptrT sp){if (_ptr ! sp._ptr){if (--(*_pcount) 0){delete _ptr;delete _pcount;}_ptr sp._ptr;_pcount sp._pcount;(*_pcount);}return *this;}~shared_ptr(){if (--(*_pcount) 0){cout delete: _ptr endl;//delete _ptr;_del(_ptr);delete _pcount;}}T* get()const{return _ptr;}T operator*(){return *_ptr;}T* operator-(){return _ptr;}private:T* _ptr;int* _pcount;functionvoid(T*) _del;//本来就要传仿函数进来而且也不止类型刚好知道返回值和参数可以使用包装器};xdh::shared_ptrA sp2(new A[5], [](A* ptr) { delete[] ptr; });//使用lambda表达式也行到这里我们的定制删除器就讲解结束大家下来好好的去看看。 四、总结 今天讲解内容非常多但是非常使用他是以后你在公司可以避免事故的一个重要东西因为内存泄漏是一个非常不好的问题而智能指针可以很好的避免这样的问题出现所以还是希望大家多去了解了解再智能指针这环节还有一些知识点没讲到博主后面都会补充到的这篇我们就讲到这里我们下篇再见
http://www.pierceye.com/news/809965/

相关文章:

  • 亳州网站开发公司wordpress 添加分享
  • 如何查询网站接入信息移动网站开发框架
  • 河南做网站的百度竞价推广收费标准
  • 深圳的深圳的网站建设公司校园网站建设方向
  • 电商网站建设 解决方案的设计营销策略都有哪些方面
  • 菏泽网站建设兼职凡科网制作网站教程
  • 实验一 电子商务网站建设与维护北京网站设计培训学校
  • 周到的网站建设合肥建筑网站大全
  • 国外互联网资讯网站南宁网站制作费用
  • 建设公司网站要注意哪些蜜雪冰城推广软文
  • 做信息安全的网站博客网站的建设
  • 门户网站建设项目书提升学历是什么意思
  • 上海网站建设极简慕枫塘沽有哪些互联网公司
  • 社区网站如何做官方网站建设哪儿有
  • 做兼职的网站策划书大连中山网站建设
  • 中国摄影网站深圳网站建设龙华
  • 个人网站怎么建立深圳网站建站费用
  • 笔趣阁建站教程网页设计 网站建设啥意思
  • 海门网站开发西安响应式网站建设服务提供商
  • 自适应网站建站哈尔滨市建设安全监察网站
  • nas服务器可以做网站吗电商类网站开发方案
  • 免费的个人的网站网站建设 考虑
  • 医院网站建设的目的高端网站有哪些优势
  • 佛山网站建设首选如何备份wordpress
  • 优化稳定网站排名网站建设需要学什么语言
  • 可以做设计私单的网站硬件开发工程师面试
  • 竞价网站单页网页设计师中级证书有用吗
  • 做网站 简单外包wordpress 插件api
  • 白城网站seo新手怎么建立自己网站
  • 建立用模板建立网站wordpress feed