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

网站开发私活分成济南设计公司招聘信息

网站开发私活分成,济南设计公司招聘信息,俄罗斯最新消息军事,武清区网站建设目录 一. 智能指针初识 1.1 什么是智能指针 1.2 智能指针历史历程 1.3 为什么需要智能指针 1.3.1 内存泄漏 1.3.2 防止内存泄漏 1.3.3 异常的重新捕获 二. 智能指针的原理与使用 2.1 智能指针的原理 2.2 智能指针的使用 2.3 智能指针的拷贝问题…目录 一.   智能指针初识 1.1   什么是智能指针 1.2   智能指针历史历程 1.3   为什么需要智能指针 1.3.1   内存泄漏 1.3.2   防止内存泄漏 1.3.3   异常的重新捕获 二.   智能指针的原理与使用 2.1   智能指针的原理 2.2   智能指针的使用 2.3   智能指针的拷贝问题 三.   智能指针的众多版本 3.1   auto_ptr 3.2   unique_ptr 3.3   shared_ptr 3.3.1   基础实现  3.3.2   shared_ptr的循环引用 四.   定制删除器 4.1   定制删除器的使用 4.2   定制删除器的模拟实现 4.2.1   按照库的实现  4.2.2   不按照库的实现 一.   智能指针初识 1.1   什么是智能指针 智能指针不是指针是一个管理指针的类用来存储指向动态分配对象的指针负责自动释放动态分配的对象防止堆内存泄漏和空悬指针等等问题。 动态分配的资源交给一个类对象去管理当类对象声明周期结束时自动调用析构函数释放资源。 1.2   智能指针历史历程 C 98 中产生了第一个智能指针auto_ptr。Cboost给出了更加实用的scoped_ptr防止拷贝 和 shared_ptr引进引用计数 和 weak_ptr。C 11 引入了unquie_ptr 和 shared_ptr 和 weak_ptr .需要注意的是unique_ptr对应的是boost中的scoped_ptr。并且这些智能指针的实现是参照boost中的实现的。 1.3   为什么需要智能指针 1.3.1   内存泄漏 我们在讲为什么之前先来了解一下什么是内存泄漏。 内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。 内存泄漏并不是指内存在物理上的消失而是应用程序分配某段内存后因为设计错误失去了对 该段内存的控制因而造成了内存的浪费。 内存泄漏的危害长期运行的程序出现内存泄漏影响很大如操作系统、后台服务等等出现 内存泄漏会导致响应越来越慢最终卡死。 1.3.2   防止内存泄漏 我们来看看这一个代码 void fxx() {int* p1 new int[10];int* p2 new int[20];int* p3 new int[30];//...delete[] p1;delete[] p2;delete[] p3; } 如果指针p2或者p3开辟空间new错误这里就会导致后面的delete不会被执行这就导致了指针p1的内存泄漏。这里我们可以用异常来解决但是很难看 void fxx() {int* p1 new int[10];int* p2, *p3;try{p2 new int[20];try {p3 new int[30];}catch (...){delete[] p1;delete[] p2;throw;}}catch (...){delete[] p1;throw;}//...delete[] p1;delete[] p2;delete[] p3; } 1.3.3   异常的重新捕获 我们之前一个博客http://t.csdnimg.cn/6jA1U在异常的描述中说了在异常的重新抛出与捕获中可以用智能指针解决。我们来看看 double Division(int a, int b) {// 当b 0时抛出异常if (b 0){throw Division by zero condition!;}return (double)a / (double)b; }void fyy() noexcept {int len, time;cin len time;cout Division(len, time) endl; }void func() {//这里可以看到如果发生除0错误抛出异常下面的array数组就没有得到释放//所以这里捕获异常但是不处理异常异常还是交给外面处理这里捕获了再抛出去//就能delete array了int* array new int[10];try{fyy();}catch (...){//捕获异常不是为了处理异常//是为了释放内存然后异常再重新抛出cout delete[] array endl;delete[] array;throw;//捕到什么抛什么}cout delete[] array endl;delete[] array; } 但是当有很多个变量要new和delete呢就跟上面一样会导致代码的繁琐嵌套所以我们要用智能指针来解决。 二.   智能指针的原理与使用 2.1   智能指针的原理 智能指针的基本原理是利用RAII。 RAIIRAIIResource Acquisition Is Initialization是一种利用对象生命周期来控制程序资源如内存、文件句柄、网络连接、互斥量等等的简单技术。 在对象构造时获取资源接着控制对资源的访问使之在对象的生命周期内始终保持有效最后在 对象析构的时候释放资源。借此我们实际上把管理一份资源的责任托管给了一个对象。这种做 法有两大好处 不需要显式地释放资源。采用这种方式对象所需的资源在其生命期内始终保持有效。 templateclass T class Smartptr { public://RAIISmartptr(T* ptr):_ptr(ptr){}~Smartptr(){cout delete: _ptr endl;delete _ptr;}//像指针一样T operator*(){return *_ptr;}T* operator-(){return _ptr;} private:T* _ptr; };int main() {Smartptrint sp1(new int(1));Smartptrint sp2(new int(2));*sp1 10;Smartptrpairstring, int sp3(new pairstring, int);sp3-first apple;sp3-second 1;return 0; } 2.2   智能指针的使用 templateclass T class Smartptr { public://RAIISmartptr(T* ptr):_ptr(ptr){}~Smartptr(){cout delete: _ptr endl;delete _ptr;}//像指针一样T operator*(){return *_ptr;}T* operator-(){return _ptr;} private:T* _ptr; };int div() {int a, b;cin a b;if (b 0){throw invalid_argument(除0错误);}return a / b; } void func() {Smartptrint sp1(new int(1));Smartptrint sp2(new int(2));*sp1 10;cout div() endl; } int main() {try{func();}catch (const exception e){cout e.what() endl;}return 0; } 通过SmartPtr对象无论程序是正常执行结束还是因为某些中途原因进行返回或者抛出异常等开始所面临的困境只要SmartPtr对象的生命周期结束就会自动调用对应的析构函数不会造成内存泄漏完成资源释放。 2.3   智能指针的拷贝问题 如果我们用一个智能指针拷贝构造一个智能指针或者用一个智能指针赋值给另一个智能指针。这样的操作都会导致程序崩溃。 void test() {SmartPtrint sp1(new int);SmartPtrint sp2(sp1);//拷贝构造SmartPtrint sp3(new int);SmartPtrint sp4 sp3;//赋值 }因为对于我们的智能指针来说将sp1拷贝给sp2操作是浅拷贝是将两个指针的指向统一到一块空间。当sp1和sp2释放时会导致这块空间释放两次。同样的道理将sp3赋值给sp4的时候也只是单纯的将指针的指向指到同一块空间这样在析构的时候也会导致析构两次。 所以对于如何解决这个问题智能指针分为了很多版本。 三.   智能指针的众多版本 C中存在4种智能指针auto_ptr,unquie_ptr,shared_ptr,weak_ptr他们各有优缺点以及对应的实用场景。 3.1   auto_ptr auto_ptr 管理权转移被拷贝对象把资源管理权转移给拷贝对象导致被拷贝对象悬空。 auto_ptr是C98的通过管理权转移的方式解决智能指针拷贝问题保证了一个资源只有一个对象对其进行管理这时候一个资源就不会被多个释放 int main() {yjy::auto_ptrint ap1(new int(1));yjy::auto_ptrint ap2(ap1);*ap2 10;//ap1悬空//*ap1 10;return 0; } auto_ptr的模拟实现为 namespace yjy {templateclass Tclass auto_ptr{public://RAIIauto_ptr(T* ptr):_ptr(ptr){}//ap2(ap1)auto_ptr(auto_ptrT ap){_ptr ap._ptr;ap._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(){cout delete: _ptr endl;delete _ptr;}//像指针一样T operator*(){return *_ptr;}T* operator-(){return _ptr;}private:T* _ptr;}; } 构造对象获取资源析构对象释放资源。对*和-运算符进行重载使其像指针一样。拷贝构造函数用传入的对象的资源来构造当前对象并将传入对象管理资源指针悬空。 3.2   unique_ptr 需要引用memory库来使用。 unique_ptr是C11中的智能指针unique_ptr来的更直接直接防止拷贝的方式解决智能指针的拷贝问题简单而又粗暴防止智能指针对象拷贝保证资源不会被多次释放但是防止拷贝也不是解决问题的好办法因为在很多场景下是需要拷贝的。 int main() {yjy::unique_ptrint sp1(new int(1));yjy::unique_ptrint sp2(new int(10));sp1 sp2;return 0; } 模拟实现如下 namespace yjy {templateclass Tclass unique_ptr{public://RAIIunique_ptr(T* ptr):_ptr(ptr){}//up2(up1)unique_ptr(const unique_ptrT up) delete;unique_ptrT operator(const unique_ptrT up) delete;~unique_ptr(){cout delete: _ptr endl;delete _ptr;}//像指针一样T operator*(){return *_ptr;}T* operator-(){return _ptr;}private:T* _ptr;}; } 为了禁止拷贝所以我们C98的方式是将拷贝构造函数和拷贝赋值函数声明为私有;C11的方式就直接在这两个函数后面加上delete。 3.3   shared_ptr 3.3.1   基础实现  shared_ptr是C11的智能指针通过引用计数的方式解决智能指针的拷贝问题。 shared_ptr在其内部给每个资源都维护了着一份计数用来记录该份资源被几个对象共 享。在对象被销毁时(也就是析构函数调用)就说明自己不使用该资源了对象的引用计数减 一。如果引用计数是0就说明自己是最后一个使用该资源的对象必须释放该资源如果不是0就说明除了自己还有其他对象在使用该份资源不能释放该资源否则其他对 象就成野指针了。 引用计数的方式能够支持多个对象一起管理一个资源也就支持智能指针的拷贝只有当资源的引用计数减为0时才会释放保证了同一个资源不会被多次释放 int main() {yjy::shared_ptrint sp1(new int(1));cout sp1.use_count() endl;yjy::shared_ptrint sp2(sp1);cout sp2.use_count() endl;*sp2 10;*sp1 10;yjy::shared_ptrint sp3(new int(2));yjy::shared_ptrint sp4(sp2);cout sp3.use_count() endl;return 0; } 模拟实现如下 namespace yjy {templateclass Tclass shared_ptr{public:// RAII// 保存资源shared_ptr(T* ptr):_ptr(ptr), _pcount(new int(1)){}// 释放资源~shared_ptr(){Release();}shared_ptr(const shared_ptrT sp):_ptr(sp._ptr), _pcount(sp._pcount){(*_pcount);}void Release(){if (--(*_pcount) 0){delete _pcount;delete _ptr;}}//sp1 sp1;//sp1 sp2;//sp2如果是sp1的拷贝呢shared_ptrT operator(const shared_ptrT sp){if (_ptr ! sp._ptr)//资源地址不一样{Release();_pcount sp._pcount;_ptr sp._ptr;(*_pcount);}return *this;}int use_count(){return *_pcount;}// 像指针一样T operator*(){return *_ptr;}T* operator-(){return _ptr;}T operator[](size_t pos){return _ptr[pos];}private:T* _ptr;int* _pcount;}; } 构造函数获取资源时同时将对应于的引用计数设为1表示当前一个对象在管理这块资源。析构函数将管理资源对应的引用计数--,如果为0就需要进行释放。拷贝构造函数中与传入对象一起管理资源将该资源的引用计数。对于拷贝赋值先将当前对象管理的资源对应的引用计数–为0时需要释放然后在传入对象一起管理资源。将该资源对应的引用计数。 为什么引用计数要用指针 首先引用计数可不能用int整型来表示这样的话每个对象都有一个单独的引用计数。而我们要求当多个对象管理一个资源的时候应该是引用的同一个引用计数。其次引用计数也不能设置为静态的这样的话结果是同一个类创建的对象都是同一个引用计数即管理不同资源的对象引用了同一个引用计数。而我们要求的是一个资源对应一个引用计数。 3.3.2   shared_ptr的循环引用 我们来讲一下shared_ptr的美中不足的地方循环引用 struct ListNode {int _val;yjy::shared_ptrListNode _next;yjy::shared_ptrListNode _prev;ListNode(int val 0):_val(val){}~ListNode(){cout ListNode endl;} };int main() {yjy::shared_ptrListNode n1(new ListNode(10));yjy::shared_ptrListNode n2(new ListNode(20));cout n1.use_count() endl;cout n2.use_count() endl;n1-_next n2;n2-_next n1;cout n1.use_count() endl;cout n2.use_count() endl;return 0; } 我们可以看到定义了两个对象对象里面的prev和next对应指向另一个对象这时候我们的shared_ptr就会存在缺陷。 在我们出作用域销毁的时候会发生下面的情况 n2对象销毁时-》_prev指针释放-》n1对象销毁-》_next指针释放-》n2对象销毁 可以看看运行情况 可以看见销毁时是出错了的。 可以看到这个销毁的过程是一个互相影响的过程是一个死循环。这样的结构就是我们的循环引用。该怎么办呢 这里就要用到我们的weak_ptr: //不支持RAII不参与资源管理 templateclass T class weak_ptr { public://RAIIweak_ptr():_ptr(nullptr){}weak_ptr(const shared_ptrT wp){_ptr wp.get();}weak_ptrT operator(const shared_ptrT wp){_ptr wp.get();return *this;}// 像指针一样T operator*(){return *_ptr;}T* operator-(){return _ptr;} private:T* _ptr; }; 这里的weak_ptr就不涉及RAII不参与资源管理从根源上杜绝了这个问题 struct ListNode {int _val;yjy::weak_ptrListNode _next;yjy::weak_ptrListNode _prev;ListNode(int val 0):_val(val){}~ListNode(){cout ListNode endl;} };int main() {yjy::shared_ptrListNode n1(new ListNode(10));yjy::shared_ptrListNode n2(new ListNode(20));cout n1.use_count() endl;cout n2.use_count() endl;n1-_next n2;n2-_next n1;cout n1.use_count() endl;cout n2.use_count() endl;return 0; } 这样就好了。 四.   定制删除器 4.1   定制删除器的使用 智能指针该如何辨别我们的资源是用new int开辟的还是new int[]开辟的呢要知道[]必须与delete[]匹配否则会有未知错误的这个问题我们就交给定制删除器来解决 这个del参数就是定制删除器是一个可调用对象比如函数指针、仿函数、lambda表达式以及被包装器包装后的可调用对象。 当shared_ptr对象的生命周期结束时就会调用传入的删除器完成资源的释放调用该删除器时会将shared_ptr管理的资源作为参数进行传入。 所以当资源不是以new的形式开辟的时候就要传特定的定制删除器。 比如 templateclass T struct DeleteArray {void operator()(T* ptr){delete[] ptr;} };struct ListNode {int _val;yjy::weak_ptrListNode _next;yjy::weak_ptrListNode _prev;ListNode(int val 0):_val(val){}~ListNode(){cout ListNode endl;} };int main() {yjy::shared_ptrListNode, DeleteArrayListNode n2(new ListNode[10]);return 0; } 4.2   定制删除器的模拟实现 4.2.1   按照库的实现  这是按照库的实现方法来的。可以看到模板参数定制删除器是在构造函数的。  templateclass T class shared_ptr { public:templateclass D//为了跟库保持一致我们在此处定义模板shared_ptr(T* ptr, D del)//定制删除器:_ptr(ptr), _pcount(new int(1)), _del(del){}//RAIIshared_ptr(T* ptr nullptr):_ptr(ptr), _pcount(new int(1)){}//sp2(sp1)shared_ptr(const shared_ptrint sp){_ptr sp._ptr;_pcount sp._pcount;(*_pcount);}void release(){//说明最后一个管理对象析构了可以释放资源了if (--(*_pcount) 0){cout delete: _ptr endl;//delete _ptr_del(_ptr);delete _pcount;}}//sp1sp4//sp4sp4//sp1sp2shared_ptrT operator(const shared_ptr sp){//if(this!sp)if (_ptr ! sp._ptr){release();_ptr sp._ptr;--(*_pcount);_pcount sp._pcount;//拷贝时计数(*_pcount);}return *this;}~shared_ptr(){//析构时--计数计数减到0release();}int use_count(){return *_pcount;}// 像指针一样T operator*(){return *_ptr;}T* operator-(){return _ptr;}T* get() const{return _ptr;} private:T* _ptr;int* _pcount;functionvoid(T*) _del [](T* ptr) {delete ptr; }; };int main() {yjy::shared_ptrListNode p1(new ListNode(10));yjy::shared_ptrListNode p2(new ListNode[10], DeleteArrayListNode());yjy::shared_ptrFILE p3(fopen(Test.cpp, r), [](FILE* ptr) {fclose(ptr); });return 0; } nwe[]申请内存空间必须以delete[]方式进行释放文件指针要fclost进行释放。 4.2.2   不按照库的实现 下面是不按照库的实现方法 template class Tstruct Delete{void operator()(T* ptr){delete ptr;}};templateclass T,class DDeleteTclass shared_ptr{public:shared_ptr(T* ptr):_ptr(ptr),_pcount(new int(1)){}shared_ptr(const shared_ptrT sp){_ptr sp._ptr;_pcount sp._pcount;(*_pcount);}void release(){//说明最后一个管理对象析构了可以释放资源了if (--(*_pcount) 0){cout delete: _ptr endl;//delete _ptr_del(_ptr);delete _pcount;}}//sp1sp4//sp4sp4//sp1sp2shared_ptrT operator(const shared_ptr sp){//if(this!sp)if(_ptr!sp._ptr){release();_ptr sp._ptr;--(*_pcount);_pcount sp._pcount;//拷贝时计数(*_pcount);}return *this;}~shared_ptr(){//析构时--计数计数减到0release();}int use_count(){return *_pcount;}// 像指针一样T operator*(){return *_ptr;}T* operator-(){return _ptr;}T* get() const{return _ptr;}private:T* _ptr;int* _pcount;D _del;}; 那我们main函数传参的时候就要变换一下 int main() {yjy::shared_ptrListNode, DeleteArrayListNode n2(new ListNode[10]);return 0; } 总结 好了到这里今天的知识就讲完了大家有错误一点要在评论指出我怕我一人搁这瞎bb没人告诉我错误就寄了。 祝大家越来越好不用关注我疯狂暗示
http://www.pierceye.com/news/761570/

相关文章:

  • 酒类网站建设方案案中山网站建设公司排名
  • wordpress怎么做子页面如何刷seo关键词排名
  • 网站怎样做免费优化有效果成都十大好的装修公司
  • 网站外链分析工具新闻发布会主持词
  • 网站开发哪个工具学做网站需要懂什么
  • 一般做推广网站的客户需求仕什么赣州市城乡建设局官方网站
  • 中山网站搜索引擎优化婚庆策划公司的商业模式
  • 百度云主机做网站天津展示型网站建设外包
  • 做公司网站利润营销型企业网站系统模板下载
  • 怎样在绍兴e网做网站衡水网站优化
  • 网站建设现在还有没有市场优秀网站建设报价
  • 兰州网站维护公司网站规划有哪些内容
  • 简单展示网站模板电脑网页打不开
  • 陕西省建设局网站手把手教 个人网站开发
  • 重庆网站制作网站后台上传缩略图
  • 红谷滩园林建设集团有限公司 网站大气网络公司网站模板
  • 淮安市网站东莞关键词排名seo
  • 网站建设制作设计seo优化湖南个人信用信息服务平台
  • 运营网站wordpress改了固定链接
  • 咸阳市住房和城乡建设局网站网站建设外包必须注意几点
  • 沭阳三剑客做网站小熊代刷推广网站
  • 手机网站怎么建设网站快速设计
  • 上海高端网站建设有关网站设计与制作的论文
  • wps2016怎么做网站企业主题展厅设计公司
  • 网页设计与网站建设实训目的wordpress 别名插件
  • 做婚庆网站的功能定位5分钟建站wordpress
  • 淄博网站制作优化北京高端网页
  • 专业网站设计速寻亿企邦wordpress下载官网
  • 水网站源码网站建设客户合同
  • 网站制作遨游免费企业网站备案查询