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

提供手机网站怎么做20元备案域名

提供手机网站怎么做,20元备案域名,网站建设 创意视频,小程序开发模板源码文章目录 1、为什么需要智能指针#xff1f;2、内存泄漏3、智能指针的使用及原理1、RAII思想2、拷贝问题1、unique_ptr2、shared_ptr1、多线程2、循环引用3、定制删除器 1、为什么需要智能指针#xff1f; 看一个场景 int div() {int a, b;cin a b;if (b… 文章目录 1、为什么需要智能指针2、内存泄漏3、智能指针的使用及原理1、RAII思想2、拷贝问题1、unique_ptr2、shared_ptr1、多线程2、循环引用3、定制删除器 1、为什么需要智能指针 看一个场景 int div() {int a, b;cin a b;if (b 0)throw invalid_argument(除0错误);return a / b; }void Func() {int* p1 new int;int* p2 new int;cout div() endl;delete p1;delete p2; }int main() {try{Func();}catch (exception e){cout e.what() endl;}return 0; }new是可能开辟失败抛异常的。上述代码中如果p1抛异常那么可以外面的catch可以捕获到打印出消息如果p1异常p2也要抛异常那么在这之前应当销毁p1再去抛同理到了div()那里如果也抛异常那么得销毁p1和p2整体就得这样写 void Func() {// 1、如果p1这里new 抛异常会如何// 2、如果p2这里new 抛异常会如何// 3、如果div调用这里又会抛异常会如何int* p1 new int;try{int* p2 new int;}catch (...){delete p1;throw;}try{cout div() endl;}catch (...){delete p1;delete p2;throw;}delete p1;delete p2; }一下子就能看出来这太麻烦了如果有多个new呢 2、内存泄漏 Windows和Linux都有检测内存泄漏的工具不过Windows下的VLD不太靠谱Linux中valgrind是比较出名的 Linux下几款C程序中的内存泄露检查工具 为了预防内存泄漏常用的办法就是用智能指针或者事后检测。 3、智能指针的使用及原理 1、RAII思想 template class T class SmartPtr { public:SmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){if (_ptr){cout _ptr endl;delete _ptr;}}private:T* _ptr; };void Func() {SmartPtrint sp1(new int);SmartPtrint sp2(new int);cout div() endl; }和封装锁的思路来类似都是RAII。用临时变量来构造出了作用域就自动销毁。 RAII利用对象生命周期来控制程序资源对象构造时获取资源析构时释放资源 上面的SmartPtr不像一个指针它不能解引用数据不过我们可以写对应的函数。 T operator*(){return *_ptr;}T* operator-(){return _ptr;}cout *sp1 endl;//如果模板参数是自定义类型的话就可以用-了。2、拷贝问题 智能指针如何拷贝 int main() {SmartPtrint sp1(new int(1));SmartPtrint sp2(sp1);return 0; }采用默认拷贝会浅拷贝导致同一空间重复释放。这里应当如何写拷贝构造是要用深拷贝吗其实不是我们要的浅拷贝sp1和sp2指向同一个资源以前的链表等这些迭代器结构不需要释放资源而智能指针需要管理资源所以不能单纯地浅拷贝但是又不能要深拷贝。 C98时已经有智能指针了那个版本中有一个auto_ptr它的方法是管理权转移我们写到SmartPtr类中 //管理权转移auto_ptr(auto_ptrT ap):_ptr(ap._ptr){ap._ptr nullptr;}auto_ptrint sp2(sp1);这样看就像是用ap指向sp1然后用sp1的_ptr来初始化sp2的_ptr然后把sp1的_ptr给置空。虽然看起来是可以的能解决问题但有很大隐患这会导致sp1悬空如果不知道管理权转移的实际写法那么下面代码中如果有*sp1就出问题了。程序员用它的时候需要时刻提醒自己被拷贝对象已经悬空了不能去解引用它。 在C11之前有个可移植的C库——Boost库不是标准库但也胜似标准库是有C标准委员会库工作组成员发起的C中有很多标准都从Boost中吸收过来像右值引用线程库。Boost库有scoped_ptrweak_ptr_shared_ptrC11中把scoped_ptr改名成unique_ptr。 1、unique_ptr 它的思路是防拷贝。 //防拷贝//C98思路只声明不实现但是还可以在外面强行定义所以会把它放在私有里//C11思路函数后 delete//这里拷贝构造和赋值都写上unique_ptr(const unique_ptrT up) delete;unique_ptrT operator(const unique_ptrT up) delete;不需要拷贝的场景就用它。 2、shared_ptr 引用计数的思路。有多少个指针指向一个空间那么这个空间的引用计数就是多少。当一个指针要释放时如果引用计数大于0那就不做操作如果等于0那就做一次释放资源这个空间的指针也都用完了。 引用计数这个变量不能放在静态区因为如果static修饰后它属于类的每个对象但我们要的是指向同一空间的所有指针。定义一个int* pcount。 shared_ptr(T* ptr):_ptr(ptr), _pcount(new int(1)){}~shared_ptr(){if (--(*_pcount) 0){cout _ptr endl;delete _ptr;delete _pcount;}}shared_ptr(const shared_ptrT sp):_ptr(sp._ptr), _pcount(sp._pcount){(*_pcount);}赋值函数比如sp1 sp3那么sp1的引用计数需要–因为它要指向新空间了假设sp1的空间还有别的指针指向而sp3的空间只有sp3这一个指针sp3 sp1那么就是sp3–。 shared_ptrT operator(const shared_ptrT sp){if (_ptr ! sp._str){if (--(*_pcount) 0)//处理空间上只有一个指针的情况{delete _ptr;delete _pcount;}_ptr sp._ptr;_pcount sp._pcount;(*_pcount);}return *this;}1、多线程 整体改成这样的形式来配合加锁 shared_ptr(T* ptr):_ptr(ptr), _pcount(new int(1)){}void Release(){if (--(*_pcount) 0){if(_ptr)//如果为空那就不需要释放{delete _ptr;}delete _pcount;}}void AddCount(){(*_pcount);}~shared_ptr(){Release();}shared_ptr(const shared_ptrT sp):_ptr(sp._ptr), _pcount(sp._pcount){AddCount();}shared_ptrT operator(const shared_ptrT sp){if (_ptr ! sp._str){Release();_ptr sp._ptr;_pcount sp._pcount;AddCount();}return *this;}多线程比较常见的场景就是线程安全问题。同一个数会出现多次操作导致结果不是我们想要的。多线程情况下像传给接收引用的参数时要写成ref(…)ref是库中的函数否则会被认为是传值传参。 template class T class shared_ptr { public:shared_ptr(T* ptr):_ptr(ptr), _pcount(new int(1)), _pmtx(new mutex){}void Release(){_pmtx.lock();if (--(*_pcount) 0){if(_ptr){delete _ptr;}delete _pcount;}_pmtx.unlock();}void AddCount(){_pmtx.lock();(*_pcount);_pmtx.unlock();}~shared_ptr(){Release();}shared_ptr(const shared_ptrT sp):_ptr(sp._ptr), _pcount(sp._pcount), _pmtx(sp._pmtx){AddCount();}shared_ptrT operator(const shared_ptrT sp){if (_ptr ! sp._str){Release();_ptr sp._ptr;_pcount sp._pcount;_pmtx sp-_pmtx;AddCount();}return *this;}//防拷贝//C98思路只声明不实现但是还可以在外面强行定义所以放在私有里//C11思路函数后 delete//unique_ptr(const unique_ptrT up) delete;//unique_ptrT operator(const unique_ptrT up) delete;T operator*(){return *_ptr;}T* operator-(){return _ptr;} private:T* _ptr;int* pcount;mutex* _pmtx; };在Release那里到了引用计数减到0时需要释放引用计数释放锁。如果是在if里释放锁那么外面的解锁操作就有问题了。 解决办法是可以设置一个状态位 void Release(){_pmtx.lock();bool deleteFlag false;if (--(*_pcount) 0){if(_ptr){delete _ptr;}delete _pcount;deleteFlag true;}_pmtx.unlock();if (deleteFlag){delete _pmtx;}}shared_ptr本身是线程安全的因为计数是加锁保护的它实例化的对象不是线程安全的想要线程安全那么在对对象操作时用锁保护就行。 2、循环引用 写一个场景还是用上面的shared_ptr template class T class shared_ptr { public:shared_ptr(T* ptr):_ptr(ptr), _pcount(new int(1)), _pmtx(new mutex){}void Release(){_pmtx.lock();bool deleteFlag false;if (--(*_pcount) 0){if (_ptr){delete _ptr;}delete _pcount;deleteFlag true;}_pmtx.unlock();if (deleteFlag){delete _pmtx;}}void AddCount(){_pmtx.lock();(*_pcount);_pmtx.unlock();}~shared_ptr(){Release();}shared_ptr(const shared_ptrT sp):_ptr(sp._ptr), _pcount(sp._pcount), _pmtx(sp._pmtx){AddCount();}shared_ptrT operator(const shared_ptrT sp){if (_ptr ! sp._str){Release();_ptr sp._ptr;_pcount sp._pcount;_pmtx sp-_pmtx;AddCount();}return *this;}//防拷贝//C98思路只声明不实现但是还可以在外面强行定义所以放在私有里//C11思路函数后 delete//unique_ptr(const unique_ptrT up) delete;//unique_ptrT operator(const unique_ptrT up) delete;T operator*(){return *_ptr;}T* operator-(){return _ptr;} private:T* _ptr;int* pcount;mutex* _pmtx; };struct ListNode {ListNode* _next;ListNode* _prev;int _val;~ListNode(){cout ~ListNode endl;} };int main() {shared_ptrListNode n1 new ListNode;shared_ptrListNode n2 new ListNode;return 0; }当尝试连接两个节点时就发生了错误 n1-_next n2;n2-_prev n1;n1和n2是智能指针类型而next和prev是ListNode类型的无法赋值那把ListNode里的两个指针换成shared_ptr ListNode 类型的但这样还不行因为我们在定义next和prev时没有传参是无参构造所以在智能指针的类里应当写上缺省参数。 shared_ptr(T* ptr nullptr):_ptr(ptr), _pcount(new int(1)), _pmtx(new mutex){}struct ListNode {shared_ptrListNode _next;shared_ptrListNode _prev;int _val;~ListNode(){cout ~ListNode endl;} };现在有一个问题 n1-_next n2;n2-_prev n1;如果两句都写程序会不释放资源而如果只写一句或者两句都不写那就会释放资源就会打印~ListNode使用库中的智能指针也是这样这就是智能指针引起的循环引用问题。 n1和n2都有各自的next和prev如果不相互连接也就是什么都不写那么next和prev随着n1n2销毁而销毁。 写了一句比如n1-_next n2那么n2这个节点除了它本身还有n1的next指向它n2析构时引用计数–但是空间不销毁n1析构时里面的成员变量也会随着析构那么整体也可以完好地退出。 但是两句都写就出问题了。 n1-_next n2;n2-_prev n1;出了作用域n2先析构引用计数–但是还不能销毁空间引用计数没有为0也还有一个指针指向它n1析构时n1也是一样也不能析构引用计数–现在这两个空间的引用计数都为1n1的next指向n2的空间n2的prev指向n1的空间那么n1这个空间什么时候析构要看prevprev析构n1这个空间就析构但是n2这个空间由next指向next析构n2才能析构prev才能析构所以next和prev已经形成了相互制约的关系没办法全部析构了。这就是循环引用会导致内存泄漏。 为了解决这个问题标准库中有个weak_ptr来辅助shared_ptr也叫做弱指针。weak_ptr不是RAII的也就是它不是常规的智能指针但是支持像指针一样专门用来解决shared_ptr的辅助引用问题。用weak这样写。 struct ListNode {std::weak_ptrListNode _next;std::weak_ptrListNode _prev;int _val;~ListNode(){cout ~ListNode endl;} };weak_ptr不会增加引用计数。标准库中weak_ptr实现得很复杂我们这里只模拟实现一个简单的 template class Tclass weak_ptr{public:weak_ptr():_ptr(nullptr){}weak_ptr(const shared_ptrT sp):_ptr(sp.get()){}T operator*(){return *_ptr;}T* operator-(){return _ptr;}T* get() const{return _ptr;}int use_count(){return *_pcount;}private:T* _ptr;int* _pcount;mutex* _pmtx;};struct ListNode {zyd::weak_ptrListNode _next;zyd::weak_ptrListNode _prev;int _val;~ListNode(){cout ~ListNode endl;} };int main() {zyd::shared_ptrListNode n1 new ListNode;zyd::shared_ptrListNode n2 new ListNode;n1-_next n2;n2-_prev n1;return 0; }3、定制删除器 在实例化的时候传new int[10]这样的话可能会崩溃是因为new []会在开辟的空间前再开辟一个存放元素个数的空间但是delete的时候会从开辟的空间开始释放而不包含那个存储个数的空间所以本质上是释放的位置不对。 定制删除器本质上是一个可调用对象函数指针仿函数lambda都可以。 template class T struct DeleteArray {void operator()(T* ptr){cout 仿函数 endl;delete[] ptr;} };int main() {//zyd::shared_ptrListNode n1 new ListNode;//zyd::shared_ptrListNode n2 new ListNode;//n1-_next n2;//n2-_prev n1;std::shared_ptr(int) spa1(new int[10], DeleteArrayint());//仿函数std::shared_ptr(int) spa2(new int[10], [](int* ptr) {delete[] ptr; });//lambdareturn 0; }库中的做法是把这个删除器放到构造函数里实例化的时候传过来保存起来析构时用它去析构。这里的重点在于如何保存这个删除器。一个是我们可以在总的模板参数那里加一个模板参数那么析构函数就可以直接用也不用在构造函数那里在写上一个模板参数或者用包装器。这里写包装器。 template class Dshared_ptr(const shared_ptrT sp, D del):_ptr(sp._ptr), _pcount(sp._pcount), _pmtx(sp._pmtx), _del(del){AddCount();}void Release(){_pmtx.lock();bool deleteFlag false;if (--(*_pcount) 0){if (_ptr){//delete _ptr;_del(_ptr);}delete _pcount;deleteFlag true;}_pmtx.unlock();if (deleteFlag){delete _pmtx;}}private:T* _ptr;int* _pcount;mutex* _pmtx;functionalvoid(T*) _del;这样写其实会有问题如果用不到这个删除器就会调用默认构造删除器没有初始化到了析构时删除器就是被编译器默认初始化的用它来析构就容易出问题。我们可以用缺省 private:T* _ptr;int* _pcount;mutex* _pmtx;functionalvoid(T*) _del [](T* ptr) {cout lambda delete: ptr endl;delete ptr;};定制删除器当作了解重点在于shared_ptr的实现。 本篇gitee 结束。
http://www.tj-hxxt.cn/news/221132.html

相关文章:

  • 溧阳网站建设公司wordpress limit
  • 漳州建网站太原做手机网站设计
  • 怎么在百度上搜到自己的网站网站建设 豫icp备
  • 苏州相城网站建设网站关键词设置几个
  • 唯品会网站建设的目的如何选择网站开发
  • 佛山网站优化效果自己电脑做服务器网站吗
  • 为什么一个网站做中英文双语版人工智能培训课程
  • 网站建设学什么的工商注册费用多少钱
  • 2022年免费网站软件下载公众号模板网站
  • 国外英文网站锦州网站建设品牌好
  • 如何制作h5做网站网站编辑的栏目怎么做
  • 广告公司资质wordpress的seo收件箱
  • 网站制作的网站免费做图片链接网站
  • 推广网站建设网站开发文件综述
  • 东莞小学网站建设网站域名需要购买吗
  • 福建省教师空间建设网站精美网页源码网站
  • 毕业设计报告网站开发wordpress瓶颈
  • 网站建设与设计试题先做网站先备案
  • 做网站算新媒体运营吗网站底部版权信息格式
  • 中国做外贸网站有哪些问题网站建设公司成都案例展示
  • 淘宝客怎么做自己的网站一个网站的制作特点
  • 做网站需要的企业wordpress自动采集源码
  • 自定义内容网站龙岗 营销型网站建设
  • 专业定制网站建设seo加盟代理
  • 有什么网站帮做邀请函设计的电脑端网页设计尺寸
  • 申请网站网站甘肃省住房和建设厅网站
  • 杭州企业自助建站系统自贡建设投资有限公司网站
  • 网站常用热点hot小图标快站怎么做淘客网站
  • 红河网站建设小程序代理加盟有哪些大品牌
  • joomla构建行业网站多用户自助建站