岛国萝莉做的电影网站,做网站可以做什么,新颖的互联网公司名字,肇庆网站建设解决方案异常和智能指针 一.异常1.C/C的错误#xff1a;1.C2.C3.三个关键字#xff1a; 2.使用异常#xff1a;1.基本概念#xff1a;2.基本代码#xff1a;1.基本使用#xff1a;2.多个捕获#xff1a;3.任意类型异常的捕获#xff1a;4.异常的重新抛出#xff1a; 3.异常安全… 异常和智能指针 一.异常1.C/C的错误1.C2.C3.三个关键字 2.使用异常1.基本概念2.基本代码1.基本使用2.多个捕获3.任意类型异常的捕获4.异常的重新抛出 3.异常安全1.基本概念2.构造异常3.析构异常4.RAII的处理思路5.异常规范1.正常使用2.不正常的使用 4.自定义的异常体系5.C标准库的异常体系 二.智能指针1.为什么需要智能指针1.简单代码2.内存泄漏 2.智能指针1.简单的模拟2.auto_ptr1.简单使用2.模拟实现auto_ptr 3.unique_ptr4.shared_ptr5.weak_ptr 一.异常
1.C/C的错误
1.C 1.终止当前的程序assert断言exit退出导致程序无法运行完毕直接的退出。 2.返回错误码查找这个错误码在库中对应的是什么错误。 2.C 1.异常是一种处理错误的方式当一个函数发现出现了无法处理的情况就可以抛出一个异常让函数或者函数的调用者去处理抛出的异常。 3.三个关键字 1.throw:当出现异常的时候我们通过throw关键字去抛出一个异常。 2.catch通过catch去捕获异常可以在catch中去对捕获到的异常进行处理可以存在多个catch进行捕获。 3.trytry中的代码就是有可能存在异常的代码try后一般存在catch。 2.使用异常
1.基本概念 1.异常可以在任意一层函数调用链中去进行捕获。 2.抛出的异常类型必须使用捕获相同类型的catch去捕获。 3.抛出异常后会直接跳到捕获异常的地方去中间的函数正常结束。 4.当一个异常被抛出但是到main函数都没有被捕获程序就会报错。 5.可以写任意多个捕获。 6.catch后的代码可以正常执行。 7.抛出异常后在调用链上使用最近并且捕捉类型匹配的catch。 8.抛出异常对象会生成异常对象的拷贝捕获后异常对象会被释放。 9.catch(…)捕捉任意类型的对象。 2.基本代码
1.基本使用
#includeiostream
using namespace std;void divide()
{int a 0, b 0;cin a b;if (b 0)throw 除0错误;cout a / b endl;
}int main()
{try {divide();}catch (const char* msgerror){cout msgerror endl;}cout ----------------------------- endl;return 0;
}2.多个捕获
#includeiostream
using namespace std;void pwd()
{int a 0;cin a;//偶数错误我们不希望它是一个偶数!if (a % 2 0)throw 2;cout a: a endl;
}void divide()
{int a 0, b 0;cin a b;if (b 0)throw 除0错误;cout a / b endl;try {pwd();}catch (int x){cout 1: x endl;}}int main()
{try{divide();}catch (const char* msgerror){cout msgerror endl;}catch (int x){cout 2: x endl;}cout ----------------------------- endl;return 0;
}3.任意类型异常的捕获
#includeiostream
#includestring
using namespace std;void pwd1()
{int a 0;cin a;//偶数错误我们不希望它是一个偶数!if (a % 2 0)throw 2;cout a: a endl;
}void pwd2()
{int b 0;cin b;//奇数错误我们不希望它是一个奇数!if (b % 2 ! 0)throw string(b字符是一个奇数);cout b: b endl;
}void divide()
{int a 0, b 0;cin a b;if (b 0)throw 除0错误;cout a / b endl;pwd1();pwd2();
}int main()
{try{divide();}catch (const char* msgerror){cout msgerror endl;}catch (int x){cout 2: x endl;}catch (...){cout unknow errmsg endl;}cout ----------------------------- endl;return 0;
}//1.没有增加任意类型的异常捕获 //2.增加任意类型的异常捕获 4.异常的重新抛出 1.异常的重新抛出,往往是为了解决其他的问题不是异常本身的问题我们只是通过中间的捕获去解决其他问题之后还会把未处理的异常进行重新抛出 #includeiostream
#includestring
using namespace std;void pwd1()
{int a 0;cin a;//偶数错误我们不希望它是一个偶数!if (a % 2 0)throw 2;cout a: a endl;
}void divide()
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;try{pwd1();}catch (...){//2.空间释放delete[] pa;cout delete[] pa endl;//3.异常的重新抛出throw;}
}int main()
{try{divide();}catch (const char* msgerror){cout msgerror endl;}catch (int x){cout 2: x endl;}cout ----------------------------- endl;return 0;
}3.异常安全
1.基本概念 1.异常会导致执行流的乱跳产生异常安全的问题。 2.在构造函数的时候不要去抛出异常导致对象不完整。 3.在析构函数的时候不要去抛出异常导致内存泄漏空间没有完全释放。 2.构造异常 1.问题 2.这个对象没有开辟完整并且pa指针没有被释放导致内存泄漏。 #includeiostream
#includestring
using namespace std;void divide()
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}class A {
public:A(int n){pa new int(n);divide();pb new int(n);}~A(){delete[] pa;delete[] pb;cout delete[] pa delete[] pb endl;}
private:int* pa;int* pb;
};int main()
{try{A a(10);}catch (const char* msgerror){cout msgerror endl;}cout ----------------------------- endl;return 0;
}3.析构异常 1.问题 2.对象空间开辟完整但是pb没有被正常释放导致内存泄漏。 #includeiostream
#includestring
using namespace std;void divide()
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}class A {
public:A(int n){pa new int(n);pb new int(n);}~A(){delete[] pa;divide();delete[] pb;cout delete[] pa delete[] pb endl;}
private:int* pa;int* pb;
};int main()
{try{A a(10);}catch (const char* msgerror){cout msgerror endl;}cout ----------------------------- endl;return 0;
}4.RAII的处理思路 C中的异常经常会导致资源泄漏的问题在new和delete中抛出了异常可能导致资源泄漏lock和unlock中导致死锁的问题C经常通过RAII来解决问题。RAII在下面的智能指针中去说。 5.异常规范 1.异常规范的目的是让函数的使用者知道函数可能会抛什么类型的异常。 2.函数后面写throw()表示函数不抛异常。 3.函数后面没有写如何东西表示函数可能会抛任意类型的异常。 4.C11中新增noexcept在函数后增加表示函数不会抛异常。 1.正常使用
#includeiostream
#includestring
using namespace std;void divide() throw(const char*, int ,string)
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}int main()
{try{divide();}catch (const char* msgerror){cout msgerror endl;}catch (int msgerror){cout msgerror endl;}catch (string msgerror){cout msgerror endl;}cout ----------------------------- endl;return 0;
}2.不正常的使用
//1.假设抛AB类型的异常但是抛了C类型的异常
#includeiostream
#includestring
using namespace std;void divide() throw(int, string)
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}int main()
{try{divide();}catch (int msgerror){cout msgerror endl;}catch (string msgerror){cout msgerror endl;}cout ----------------------------- endl;return 0;
}//2.假设不抛异常但是还是抛异常了
#includeiostream
#includestring
using namespace std;void divide() throw()
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}int main()
{try{divide();}catch (const char* msgerror){cout msgerror endl;}cout ----------------------------- endl;return 0;
}//1.C11新增noexcept有一定的作用
#includeiostream
#includestring
using namespace std;void divide() noexcept
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}int main()
{try{divide();}catch (const char* msgerror){cout msgerror endl;}cout ----------------------------- endl;return 0;
}4.自定义的异常体系 1.如何统一的去管理异常的抛出类型呢 2.抛出派生类的异常可以使用基类去捕获。 #includeiostream
#includewindows.h
#includestring
using namespace std;void divide() noexcept
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}class except {
public:except(int id, const char* error):_id(id),_msgerror(error){}virtual string what(){return _msgerror;}~except(){}
private:int _id;const char* _msgerror;
};class sqlerro : public except {
public:sqlerro(int id, const char* error, const char* sqlerr):except(id, error), _sqlerr(sqlerr){}virtual string what(){string str sql message;return str;}
private:const char* _sqlerr;
};class Tcperro : public except {
public:Tcperro(int id, const char* error, const char* Tcperr):except(id, error), _Tcperr(Tcperr){}virtual string what(){string str TCP message;return str;}
private:const char* _Tcperr;
};void operator_sql(int n)
{if (n % 2 0)throw sqlerro(2, sql erro, select * from user);cout sql success endl;
}void operator_Tcp(int n)
{if (n % 3 0)throw Tcperro(2, Tcp erro, sock error);cout Tcp success endl;
}int main()
{srand(time(NULL));while (1){Sleep(1000);try{int n rand() % 100;//1.操作库operator_sql(n);//2.操作网络operator_Tcp(n);}catch (except msgerror){cout msgerror.what() endl;}}cout ----------------------------- endl;return 0;
}5.C标准库的异常体系 二.智能指针
1.为什么需要智能指针
1.简单代码 1.我们知道new函数本身就有可能抛异常当空间出现问题的时候。 2.连续的空间开辟需要像下面的代码一样进行异常的处理才不会出现问题。 3.有没有什么好的方法去管理呢 #includeiostream
#includestring
using namespace std;void divide()
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}class A {
public:A(int n){try{pa new int(n);try {pb new int(n);try{pc new int(n);}catch (...){delete[] pa;delete[] pb;}}catch (...){delete[] pa;}}}~A(){delete[] pa;delete[] pb;delete[] pc;cout delete[] pa delete[] pb endl;}
private:int* pa;int* pb;int* pc;
};int main()
{try{A a(10);}catch (...){cout new error endl;}cout ----------------------------- endl;return 0;
}2.内存泄漏 C/C程序中一般我们关心两种方面的内存泄漏 堆内存泄漏(Heap leak) 堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一 块内存用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分 内存没有被释放那么以后这部分空间将无法再被使用就会产生Heap Leak。 系统资源泄漏 指程序使用系统分配的资源比方套接字、文件描述符、管道等没有使用对应的函数释放 掉导致系统资源的浪费严重可导致系统效能减少系统执行不稳定。 2.智能指针
1.简单的模拟 RAII的原理 RAIIResource Acquisition Is Initialization是一种利用对象生命周期来控制程序资源如内存、文件句柄、网络连接、互斥量等等的简单技术。 在对象构造时获取资源接着控制对资源的访问使之在对象的生命周期内始终保持有效最后在对象析构的时候释放资源。借此我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处 1.不需要显式地释放资源。 2.采用这种方式对象所需的资源在其生命期内始终保持有效 #includeiostream
#includestring
using namespace std;void divide()
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}templateclass T
class smart_ptr {
public:smart_ptr(T* a):_ptr(a){}~smart_ptr(){if (_ptr)delete _ptr;}
private:T* _ptr;
};class A {
public:A(int n){pa new int(n);pb new int(n);}~A(){delete[] pa;delete[] pb;cout delete[] pa delete[] pb endl;}
private:int* pa;int* pb;
};int main()
{try{smart_ptrA pa new A(10);divide();}catch (...){cout new error endl;}cout ----------------------------- endl;return 0;
}2.auto_ptr
1.简单使用
#includeiostream
#includememory
#includestring
using namespace std;void divide()
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}void text()
{auto_ptrint pa(new int(10));auto_ptrint pb(new int(10));divide();
}int main()
{try{text();}catch (...){cout new error endl;}cout ----------------------------- endl;return 0;
}2.模拟实现auto_ptr auto_ptr的实现原理管理权转移的思想模拟实现了一份bit::auto_ptr来了解它的原理 using namespace std;
namespace sfpy {templateclass Tclass auto_ptr {public://1.构造auto_ptr(T* ptr):_ptr(ptr){}//2.拷贝构造auto_ptr(auto_ptrT sp):_ptr(sp._ptr){//管理权限转移sp._ptr nullptr;}//3.赋值auto_ptrT operator(auto_ptrT ap){//检查自己给自己赋值的情况if (this ! ap){//1.释放自己if (_ptr)delete _ptr;//2.管理权限转移_ptr ap._ptr;ap._ptr nullptr;}return *this;}//像指针一样T operator*(){return *_ptr;}T* operator-(){return _ptr;}//析构~auto_ptr(){if (_ptr){delete _ptr;cout delete _ptr endl;}}private:T* _ptr;};
}3.unique_ptr 简单粗暴的防止拷贝防止赋值 auto_ptr非常容易的产生了多次析构的问题 using namespace std;
namespace sfpy {templateclass Tclass unique_ptr {public://1.构造unique_ptr(T* ptr):_ptr(ptr){}//2.拷贝构造unique_ptr(auto_ptrT sp) delete//3.赋值unique_ptrT operator(unique_ptrT ap) delete//像指针一样T operator*(){return *_ptr;}T* operator-(){return _ptr;}//析构~unique_ptr(){if (_ptr){delete _ptr;cout delete _ptr endl;}}private:T* _ptr;};
}4.shared_ptr shared_ptr的原理是通过引用计数的方式来实现多个shared_ptr对象之间共享资源. shared_ptr在其内部给每个资源都维护了着一份计数用来记录该份资源被几个对象共享。在对象被销毁时(也就是析构函数调用)就说明自己不使用该资源了对象的引用计数减1。如果引用计数是0就说明自己是最后一个使用该资源的对象必须释放该资源如果不是0就说明除了自己还有其他对象在使用该份资源不能释放该资源否则其他对象就成野指针了。 #includeiostream
#includememory
#includestring
#includeshared_ptr.husing namespace std;void divide()
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}void text()
{int* a new int(10);sfpy::shared_ptrint pa(a);sfpy::shared_ptrint pb(pa);pb pa;divide();
}int main()
{try{text();}catch (...){cout new error endl;}cout ----------------------------- endl;return 0;
}#pragma once#includeiostreamusing namespace std;
namespace sfpy {templateclass Tclass shared_ptr {public://1.构造shared_ptr(T* ptr):_ptr(ptr),_pcount(new int(1)){}//2.拷贝构造shared_ptr(shared_ptrT sp):_ptr(sp._ptr),_pcount(sp._pcount){(*_pcount);}//3.赋值shared_ptrT operator(shared_ptrT ap){//检查自己给自己赋值的情况if (this ! ap){//1.原来的要减少realse();//2.新的增加_ptr ap._ptr;_pcount ap._pcount;(*_pcount);}return *this;}//像指针一样T operator*(){return *_ptr;}T* operator-(){return _ptr;}void realse(){if (_ptr *_pcount 1){delete _ptr;delete _pcount;cout delete _ptr delete _pcount; endl;}else{(*_pcount)--;}}//析构~shared_ptr(){realse();}private:T* _ptr;int* _pcount;};
}5.weak_ptr 1.产生上面问题的本质是ListNode使用了sharedptr导致引用计数不会减到0 2.所以两个节点都不能正常的释放。 3.把ListNode节点的智能指针改变为weak_ptr #includeiostream
#includeshared_ptr.hnamespace sfpy {templateclass Tclass weak_ptr{public:weak_ptr():_ptr(nullptr){}weak_ptr(const sfpy::shared_ptrT sp):_ptr(sp.get()){}weak_ptrT operator(const sfpy::shared_ptrT sp){_ptr sp.get();return *this;}T operator*(){return *_ptr;}T* operator-(){return _ptr;}private:T* _ptr;};
}#includeiostream
#includememory
#includestring
#includeweak_ptr.h
#includeshared_ptr.husing namespace std;struct ListNode {ListNode(int x):_prev(nullptr),_next(nullptr),_date(x){}sfpy::weak_ptrListNode _prev;sfpy::weak_ptrListNode _next;int _date;
};//struct ListNode {
// ListNode(int x)
// :_prev(nullptr)
// , _next(nullptr)
// , _date(x)
// {}
//
// sfpy::shared_ptrListNode _prev;
// sfpy::shared_ptrListNode _next;
// int _date;
//};void divide()
{int a 0, b 0;cin a b;//1.开辟空间int* pa new int(10);if (b 0)throw 除0错误;cout a / b endl;
}void text()
{sfpy::shared_ptrListNode pa(new ListNode(1));sfpy::shared_ptrListNode pb(new ListNode(2));pa-_next pb;pb-_prev pa;divide();
}int main()
{try{text();}catch (...){cout new error endl;}cout ----------------------------- endl;return 0;
}