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

国外网络营销网站wordpress 全版本注入

国外网络营销网站,wordpress 全版本注入,智慧团建密码只能是8位吗,株洲seo优化公司智能指针 文章目录 智能指针内存泄漏智能指针解决内存泄漏问题智能指针的使用及原理RAII智能指针对象的拷贝问题 C中的智能指针auto_ptrunique_ptrshared_ptrweak_ptr定制包装器C11和boost中智能指针的关系 内存泄漏 什么是内存泄漏#xff1a;内存泄漏指因为疏忽或错误造成程…智能指针 文章目录 智能指针内存泄漏智能指针解决内存泄漏问题智能指针的使用及原理RAII智能指针对象的拷贝问题 C中的智能指针auto_ptrunique_ptrshared_ptrweak_ptr定制包装器C11和boost中智能指针的关系 内存泄漏 什么是内存泄漏内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内 存泄漏并不是指内存在物理上的消失而是应用程序分配某段内存后因为设计错误失去了对 该段内存的控制因而造成了内存的浪费。 内存泄漏的危害长期运行的程序出现内存泄漏影响很大如操作系统、后台服务等等出现 内存泄漏会导致响应越来越慢最终卡死。 C/C程序中一般我们关心两种方面的内存泄漏 堆内存泄漏(Heap leak) 堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一 块内存用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分 内存没有被释放那么以后这部分空间将无法再被使用就会产生Heap Leak。 系统资源泄漏 指程序使用系统分配的资源比方套接字、文件描述符、管道等没有使用对应的函数释放 掉导致系统资源的浪费严重可导致系统效能减少系统执行不稳定。 内存泄漏很常见解决方案通常分为两种 事前预防型。如智能指针等。事后查错型。如泄 漏检测工具。 智能指针解决内存泄漏问题 场景main函数里调用func函数在func函数里申请了一个int大小的空间然后调用div函数在div函数进行除法操作若出现除零则直接抛异常直接跳转到main函数捕获异常从而没有释放掉在func函数内申请的资源即内存泄漏。 #includeiostream #includevector using namespace std;int div() {int a, b;cin a b;if (b 0)throw invalid_argument(除0错误);return a / b; } void func() {int* ptr new int;//new了一个int大小的资源cout div() endl;delete ptr;//因为抛异常导致这个int资源没有被正常释放cout delete ptr endl; } int main() {try{func();}catch (exception e){cout e.what() endl;}return 0; }解决方法一在func函数内捕获一次异常进行对申请资源的释放后再将异常抛出让外层栈帧去捕获解决异常。 int div() {int a, b;cin a b;if (b 0)throw invalid_argument(除0错误);return a / b; } void func() { int* ptr new int;//new了一个int大小的资源 try {cout div() endl; } catch (...) {delete ptr;//因为抛异常导致这个int资源没有被正常释放cout delete ptr endl;throw; }} int main() {try{func();}catch (exception e){cout e.what() endl;}return 0; }解决方案二让智能指针对资源进行管理调用智能指针的构造函数申请资源调用智能指针的析构函数释放资源。 templateclass T class smartptr { public:smartptr(T* ptrnullptr) :_ptr(ptr){}~smartptr(){if (_ptr){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 sma(new int);cout div() endl; } int main() {try{func();}catch (exception e){cout e.what() endl;}return 0; }在构造sma对象时让smartptr的构造函数去申请资源。当退出func函数这层栈帧时sma对象的生命周期结束自动调用smartptr的析构函数去释放资源。将申请到的资源交给一个smartptr对象进行管理这样无论是否出现除零都能正常释放资源。此外为了让smartptr对象能够像原生指针一样使用还需要对*和-运算符进行重载。 智能指针的使用及原理 RAII RAIIResource Acquisition Is Initialization是一种利用对象生命周期来控制程序资源如内 存、文件句柄、网络连接、互斥量等等的简单技术。 在对象构造时获取资源接着控制对资源的访问使之在对象的生命周期内始终保持有效最后在对象析构的时候释放资源。借此我们实际上把管理一份资源的责任托管给了一个对象。这种做 法有两大好处 不需要显式地释放资源。采用这种方式对象所需的资源在其生命期内始终保持有效。 需要注意的是 在对象构造时获取资源在对象析构时释放资源即要具备RAII特性。对*和-运算符进行重载使得对象具有像指针一样的行为。智能指针对象的拷贝问题。 智能指针对象的拷贝问题 int main() {smartptrint sm1(new int);smartptrint sm2(sm1);//拷贝构造smartptrint sm3(new int);//赋值重载sm3 sm1;return 0; }编译器默认生成的拷贝构造是对内置类型完成值拷贝浅拷贝因此sm2对象对sm1对象的拷贝构造是对sm1对象的资源的地址拷贝过来即sm1和sm2对同一份资源进行管理当退出栈帧对象的生命周期结束时sm1和sm2一起会对一份资源析构两次造成越界问题。编译器默认生产的拷贝赋值函数是对内置类型完成值拷贝浅拷贝。因此将sm1对象赋值給sm3对象是将sm1管理资源的地址赋值給sm3的_ptr即sm1和sm3对同一份资源进行管理当退出栈帧对象的生命周期结束时sm1和sm3一起会对同一份资源析构两次造成越界问题。 智能指针要模拟出原生指针的行为而我们将一个指针赋值給另一个指针其目的就是让两个指针对同一份资源进行管理但单纯的浅拷贝会导致空间多次释放因此根据实现的场景不同衍生出不同的智能指针。 C中的智能指针 auto_ptr auto_ptr的实现目的对资源的管理权进行转移 auto_ptr是C98中引入的智能指针auto_ptr通过管理权转移的方式解决智能指针的拷贝问题保证一个资源在任何时刻都只有一个对象在对其进行管理这时同一个资源就不会被多次释放了。 auto_ptr的模拟实现 templateclass T class Auto_ptr { public:Auto_ptr(T* ptrnullptr):_ptr(ptr){}~Auto_ptr() { cout delete _ptr endl; delete _ptr; }T* operator-(){return _ptr;}T operator*(){return *_ptr;}Auto_ptr(Auto_ptrT tp)//拷贝构造:_ptr(tp._ptr){tp._ptr nullptr;//悬空}Auto_ptr operator(Auto_ptrT tp){if (this!tp)//判断是否是自己赋值給自己{if (_ptr){delete _ptr;_ptr nullptr;}_ptr tp._ptr;//转移资源管理权tp._ptr nullptr;//悬空}return *this;} private:T* _ptr; };简易auto_ptr实现思路 在构造函数获取资源在析构函数释放资源利用对象的生命周期管理资源。对*和-运算符进行重载使得对象具有像指针一样的行为。在拷贝构造函数中将传入对象的资源来构造当前对象然后将传入对象管理资源的指针置空。在拷贝赋值函数中先将当前对象的资源释放然后将传入对象的资源来构造当前对象最后将传入对象管理资源的指针置空。 测试代码 int main() {Auto_ptrint apt1(new int(1));*apt1 10;Auto_ptrint apt2(apt1);Auto_ptrint apt3(new int(3));apt3 apt2;return 0; }unique_ptr unique_ptr的实现目的防止拷贝 通过防止在智能指针之间互相拷贝暴力的解决了多个智能指针对同一块资源进行释放的问题。 templateclass T class Unique_ptr { public:Unique_ptr(T* ptr):_ptr(ptr){}~Unique_ptr(){if (_ptr){cout delete _ptr endl;delete _ptr;}}T operator*(){return *_ptr;}T* operator-(){return _ptr;}Unique_ptrT operator(const Unique_ptrT upt) delete;//禁用拷贝构造Unique_ptr(const Unique_ptrT upt) delete;//禁用拷贝赋值 private:T* _ptr; };int main() {Unique_ptrint upt1(new int(1));cout *(upt1) endl;Unique_ptrint upt2(upt1);Unique_ptrint upt3(new int(3));upt3 upt1;return 0; }简易unique_ptr实现思路 在构造函数获取资源在析构函数释放资源利用对象的生命周期管理资源。对*和-运算符进行重载使得对象具有像指针一样的行为。用C98的方式将拷贝构造函数和拷贝赋值函数声明为私有或者用C11的方式在这两个函数后面加上delete防止外部调用。 shared_ptr share_ptr的实现目的是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。 namespace s {templateclass Tclass Share_ptr{public:Share_ptr(T* ptr nullptr) :_ptr(ptr), _pcount(new int(1)) {}Share_ptrT operator(const Share_ptrT spt)//赋值重载{if (_ptr ! spt._ptr){Release();_ptr spt._ptr;_pcount spt._pcount;Addpcount();}return *this;}int use_count(){return *_pcount;}void Addpcount(){(*_pcount);}Share_ptr(const Share_ptrT spt)//拷贝构造:_ptr(spt._ptr), _pcount(spt._pcount){Addpcount();}void Release(){if (--(*_pcount) 0 _ptr){//计数为0释放资源cout delete _ptr endl;delete _ptr;delete _pcount;}}~Share_ptr(){Release();}T* operator-(){return _ptr;}T* get(){return _ptr;}T operator*(){return *_ptr;}private:T* _ptr;int* _pcount;}; }int main() {s::Share_ptrint spt1(new int(1));cout spt1 pcount: spt1.use_count() endl;s::Share_ptrint spt2(spt1);cout spt2 pcount: spt2.use_count() endl;s::Share_ptrint spt3(new int(3));spt3 spt1;cout spt3 pcount: spt3.use_count() endl;return 0; }​ 简易auto_ptr实现思路 Shared_ptr在其内部给每个资源都维护了着一份计数_pcount用来记录该份资源被几个对象共 享。在构造函数中获取资源并且设置计数器_pcount为1表示当前只有自己在管理该资源。在拷贝构造函数中要与传入的对象一起管理它所管理的资源因此同时将该资源对应的计数器。在拷贝赋值函数中若在管理资源需要先放弃管理当前资源即先--_pcount,然后与传入对象一起管理传入对象所管理的资源即 _pcount。在对象被销毁时(也就是析构函数调用)就说明自己不使用该资源了对象的引用计数减 一。如果引用计数为0说明自己是最后一个使用该资源的对象这时候必须由自己释放资源如果引用计数不为0说明还有其他对象使用该资源不能释放资源否则其他对象就成野指针了对*和-运算符进行重载使得对象具有像指针一样的行为。 为什么share_ptr的引用计数要放在堆上 该引用计数不能是内置函数成员int类型的数据这样会导致每个对象都有一个引用计数而当多个对象管理同一个资源时这些对象所用的引用计数应该是同一个。 该引用计数也不能是静态变量静态变量会造成所有share_ptr类型的对象所共用同一个引用计数那么当管理不同资源时就出计数问题。 因此将shared_ptr的引用计数设置为一个指针指针指向一个计数器当一个资源第一次被管理时就去堆区开辟一块空间用于存储其对应的引用计数而当前其他对象也管理该资源时除了将该资源交给对象外该指针也要交给它其他对象就能拿到该引用计数。这时候管理同一个资源的多个对象所访问到的引用计数就是同一个管理不同资源的对象所访问的引用计数不是同一个等同于资源与其引用计数一一对应起来。 std::shared_ptr的线程安全问题 智能指针对象中引用计数是多个智能指针对象共享的两个线程中智能指针的引用计数同时或–这个操作不是原子的引用计数原来是1了两次可能还是2。这样引用计数就错乱了。会导致资源未释放或者程序崩溃的问题。所以只能指针中引用计数、–是需要加锁的也就是说引用计数的操作是线程安全的。. 智能指针管理的对象存放在堆上两个线程中同时去访问会导致线程安全问题。 首先验证C库里的shared_ptr #includeiostream #includevector #includememory #includemutex #includethread using namespace std;struct Date { public:int _year 0;int _month 0;int _day 0; }; void test_shared_ptr1() {int n 50000;mutex mtx;std::shared_ptrDate sp1(new Date);thread t1([](){for (int i 0; i n; i){std::shared_ptrDate sp2(sp1);//mtx.lock();sp2-_year;sp2-_day;sp2-_month;// mtx.unlock();}});thread t2([](){for (int i 0; i n; i){std::shared_ptrDate sp3(sp1);// mtx.lock();sp3-_year;sp3-_day;sp3-_month;// mtx.unlock();}});t1.join();t2.join();cout sp1.use_count() endl;cout sp1.get() endl;cout sp1-_year endl;cout sp1-_month endl;cout sp1-_day endl; }int main() {test_shared_ptr1(); }首先创建一个sp1对象对象管理Date结构体结构体里有三个成员变量_year、 _month、 _day。在线程thread1里sp2对象对sp1对象进行拷贝构造即sp2也同sp1一起管理同一个Date结构体并且对里面的成员变量进行加加循环500次在线程thread2里sp3对象对sp1对象进行拷贝构造即sp3也同sp1、sp2一起管理同一个Date结构体并且对里面的成员变量进行加加循环500次即sp2和sp3两个对象总和对Date对象里的成员变量加加1000次遍历完后可以看到三个参数都为1000如下图 经过多次实验可以看到存在成员对象不为1000的结果说明了shared_ptr存在线程安全问题。其根本在于多线程访问同一块资源时可能存在多个线程同时对同一个成员变量进行自增或自减操作而其操作不具备原子性。因此需要借助锁将操作的代码划分为临界区互斥锁将临界区保护起来每次只允许一个线程进入临界区访问临界资源。 struct Date { public:int _year 0;int _month 0;int _day 0; };void test_shared_ptr1() {int n 500;mutex mtx;std::shared_ptrDate sp1(new Date);thread t1([](){for (int i 0; i n; i){std::shared_ptrDate sp2(sp1);mtx.lock();sp2-_year;sp2-_day;sp2-_month;mtx.unlock();}});thread t2([](){for (int i 0; i n; i){std::shared_ptrDate sp3(sp1);mtx.lock();sp3-_year;sp3-_day;sp3-_month;mtx.unlock();}});t1.join();t2.join();cout sp1.use_count() endl;cout sp1.get() endl;cout sp1-_year: sp1-_year endl;cout sp1-_month: sp1-_month endl;cout sp1-_year: sp1-_day endl; }int main() {test_shared_ptr1(); }加互斥锁解决shared_ptr的线程安全问题 要解决引用计数的线程安全问题本质就是让对引用计数的自增和自减变成一个原子操作因此对引用计数的操作进行加锁保护将对引用计数的操作划分为临界区每次只允许一个线程进入临界区做引用计数操作。 namespace s {templateclass Tclass Share_ptr{public:Share_ptr(T* ptr nullptr) :_ptr(ptr), _pcount(new int(1)),_mut(new mutex) {}Share_ptrT operator(const Share_ptrT spt)//赋值重载{if (_ptr ! spt._ptr){Release();_ptr spt._ptr;_pcount spt._pcount;_mut spt._mut;Addpcount();}return *this;}int use_count(){return *_pcount;}void Addpcount(){_mut-lock();(*_pcount);_mut-unlock();}Share_ptr(const Share_ptrT spt)//拷贝构造:_ptr(spt._ptr), _pcount(spt._pcount),_mut(spt._mut){Addpcount();}void Release(){bool flag false;_mut-lock();if (--(*_pcount) 0 _ptr){//计数为0释放资源cout delete _ptr endl;delete _ptr;delete _pcount;flag true;}_mut-unlock();if (flag true){delete _mut;}}~Share_ptr(){Release();}T* operator-(){return _ptr;}T* get(){return _ptr;}T operator*(){return *_ptr;}private:T* _ptr;int* _pcount;mutex* _mut;}; }在shared_ptr类中新增互斥锁为了让管理同一份资源的多个对象访问到的是同一个互斥锁管理不同资源的对象访问到的不是同一个互斥锁互斥锁需要在堆区创建。在拷贝构造函数和拷贝赋值函数中除了将对应资源和引用计数交给当前对象时还需要将其资源对应互斥锁也交给当前对象。当一个资源对应的引用计数为0时除了将对应资源和引用计数释放外还需要将其资源对应的互斥锁释放。在拷贝构造函数、拷贝赋值函数、析构函数中需要对引用计数做自增或自减操作可以将其操作封装为Addpcount函数、Release函数然后只需要在这两个函数中进行加锁保护。shared_ptr只需要保证引用计数的线程安全问题而管理资源的线程安全问题由管理这块资源的操作者来保证 shared_ptr的循环引用问题 struct ListNode {int _data0;s::Share_ptrListNode _prev;s::Share_ptrListNode _next;~ListNode() { cout ~ListNode() endl; } }; int main() {s::Share_ptrListNode node1(new ListNode);s::Share_ptrListNode 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; }新建一个listNode对象让shared_ptr类node1对象管理此时node1对应的引用计数为1即listNode资源被一个shared_ptr对象管理。新建一个listNode对象让shared_ptr类node2对象管理此时node2对应的引用计数为1即listNode资源被一个shared_ptr对象管理。此时node1和node2的引用计数都为1我们不需要手动释放资源。在退出栈帧的时候会调用析构函数进行资源释放 让node1的next指向node2即node1和node2一起来管理node2所管理的资源因此node2的use_count等于2。让node2的prev指针指向node1即node1和node2一起来管理node1所管理的资源因此node1的use_count等于2。 在程序结束时会调用node1和node2的析构函数此时node1的use_count减减等于1node2的use_count减减等于1但node1无法被释放原因在于node2的prev指针指向node1想要释放node1需要先释放node2的prev指针释放node2的prev指针的前提是释放node2而node2也无法被释放原因在于node1的next指针指向node2想要释放node2需要先释放node1的next指针释放node1的next指针的前提是释放node1。因此造成了循环引用问题。 weak_ptr weak_ptr的作用为 构造出来的weak_ptr对象与shared_ptr对象管理同一份资源但不会增加这块资源对应的引用计数。weak_ptr支持用shared_ptr对象来构造weak_ptr对象weak_ptr不是用来管理资源释放的它主要是用来解决shared_ptr的循环引用问题。 namespace t {templateclass T class weak_ptr { public:weak_ptr() :_ptr(nullptr) {}weak_ptrT operator( s::Share_ptrT spt)//赋值重载{_ptr spt.get();return *this;}weak_ptr(const s::Share_ptrT spt)//拷贝构造:_ptr(spt.get()){}T* operator-(){return _ptr;}T operator*(){return *_ptr;}private:T* _ptr; }; }提供一个无参的构造函数。拷贝构造函数用shared_ptr构造weak_ptr把shared_ptr的指针传递給weak_ptrweak_ptr也能够管理shared_ptr所管理的对象。赋值重载函数用shared_ptr构造weak_ptr把shared_ptr的指针传递給weak_ptrweak_ptr也能够管理shared_ptr所管理的对象。对*和-运算符进行重载使得对象具有像指针一样的行为。shared_ptr提供一个get函数用于获取指针管理资源。 struct ListNode {int _data 0;t::weak_ptrListNode _prev;t::weak_ptrListNode _next;~ListNode() { cout ~ListNode() endl; } }; int main() {s::Share_ptrListNode node1(new ListNode);s::Share_ptrListNode node2(new ListNode);cout node1.use_count: node1.use_count() endl;cout node2.use_count: node2.use_count() endl;node1-_next node2;node2-_prev node1;cout node1.use_count: node1.use_count() endl;cout node2.use_count: node2.use_count() endl;return 0; }可以看到此时资源正常释放了。 定制包装器 当智能指针的生命周期结束所有的智能指针的析构函数都默认以delete的方式将资源释放。实际上这种方式并不好因为不是所有智能指针所管理的资源都是以new的方式创建的。比如智能指针可能管理以new[]方式创建的资源也管理的是一个文件指针。 int main() {s::Share_ptrint sp(new int[10]);s::Share_ptrint sp1(fopen(test.cpp, r));return 0; }在生命周期结束时对于以new[]方式创建的资源进行delete会造成程序崩溃因为以new[]申请到的资源必须以delete[]的方式释放。而以fopen打开的文件指针必须以fclose的方式进行关闭。 定制删除器的实现问题 C标准库中实现shared_ptr时是分成了很多个类的因此C标准库中可以将删除器的类型设置为构造函数的模板参数然后将删除器的类型在各个类之间进行传递。我们是直接用一个类来实现share_ptr,因此不能将定制删除器的类型设置为构造函数的模板参数。删除器需要在析构函数的Release函数中使用因此需要用一个成员变量将器删除器保存下来而在定义这个成员变量时就需要指定删除器的类型因此就需要給shared_ptr类再增加一个模板参数在构造shared_ptr对象时就指定删除器的类型。然后增加一个支持传入删除器的构造函数在构造shared_ptr对象时就传递删除器在释放资源时就调用该删除器即可。设置一个默认删除器当用户定义shared_ptr对象时不传入删除器就默认以delete的方式释放资源。 templateclass Tclass default_delete{public:void operator()(T* ptr){cout delete ptr endl;delete ptr;}};templateclass Tclass Delarry{public:void operator()( T* arr){cout delete[] arr endl;delete[]arr;}};templateclass T,class Ddefault_deleteTclass Share_ptr{public:Share_ptr(T* ptr ,D del) :_ptr(ptr), _pcount(new int(1)),_mut(new mutex),_del(del) {}void Release(){bool flag false;_mut-lock();if (--(*_pcount) 0 _ptr){//计数为0释放资源cout delete _ptr endl;_del( _ptr);//调用对应制定删除器释放资源delete _pcount;flag true;}_mut-unlock();if (flag true){delete _mut;}}~Share_ptr(){Release();}//......private:T* _ptr;int* _pcount;mutex* _mut;D _del;class Fclose { public:void operator()(FILE* ptr){cout fclose ptr endl;fclose(ptr);} };int main() {s::Share_ptrint,s::Delarryint sp(new int[10],s::Delarryint());s::Share_ptrFILE, functionvoid(FILE*) sp2(fopen(test.cpp, r), [](FILE* ptr) {cout fclose: ptr endl;fclose(ptr); });return 0; }C11和boost中智能指针的关系 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中的实现的。
http://www.w-s-a.com/news/770221/

相关文章:

  • 万网手机网站seo方法
  • 免费制作网站app百度首页纯净版
  • 支持api网站开发wordpress排版Markdown
  • 赤峰做网站的logo设计软件在线制作
  • iis网站批量导入苏州最新新闻事件今天
  • 甘肃省住房和城乡建设厅注册中心网站首页沈阳专业关键词推广
  • 网站怎么能在百度搜到网站开发费怎么做会计分录
  • 嘉定专业网站制作公司七星彩网站开发
  • 网站建设人员培训企业网站开发模型图
  • 自己开发一个网站应该怎么做国外设计网站 绿色的
  • 南昌外贸网站设计推广任务发布平台app
  • 建立网站成本书店网站建设可行性分析
  • 高端网站设计官网乌海学校网站建设
  • 哪些网站适合新手编程做项目优秀网页设计赏析
  • 永州网站seo德阳网站建设优化
  • 网站建设高端网站本地建设网站软件下载
  • 网站后台账号密码破解杭州酒店网站设计公司推荐
  • 和县网站开发秦皇岛建设工程信息网站
  • 国外网站用什么dns好建一个下载网站要什么cms系统
  • 礼品工艺品网站建设手机做网站哪家好
  • 泉州网站建设方案维护怎样选择网站建设
  • 江苏建站速度忿先进的网站建设
  • 广州天河建站公司com域名注册多少钱
  • 成都网站建设推广好vs2013如何做网站
  • 茶叶网站建设模板企业网站备案要多少钱
  • 怎么查网站找谁做的win主机伪静态规则 wordpress
  • 轻云服务器菁英版 多个网站北京it外包服务商
  • 售后服务 网站建设阳江seo优化
  • 网站建设后怎么赚钱wordpress调用导航栏
  • 特产网站设计六色网站