目录
throw后面可以加任意类型的对象用来抛异常:内置类型/自定义类型都可以
解释:2.被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那一个:(同一个位置不可有两个相同的捕获,只能在不同位置有捕获)
解释:4. catch(...)可以捕获任意类型的异常,只是不知道异常错误是什么。
解释:5. 可以抛出的派生类对象, 使用基类捕获,这个在实际中非常实用,我们后面会详细讲解这个。
一.异常
1.C语言传统的处理错误的方式
2. C++异常概念
throw后面可以加任意类型的对象用来抛异常:内置类型/自定义类型都可以
异常抛出直接跳到捕获的地方:
此时throw抛异常的地方直接跳到catch中,抛的异常类型要对上,所以这里跳到catch (const char* errmsg)
double Division(int a, int b)
{
// 当b == 0时抛出异常
if (b == 0)
throw "Division by zero condition!";
else
return ((double)a / (double)b);
}
void Func()
{
int len, time;
cin >> len >> time;
cout << Division(len, time) << endl;
}
int main()
{
//Func();
try
{
Func();
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
catch (int errid)
{
cout << errid << endl;
}
return 0;
}
3. 异常的使用
(1)异常的抛出和捕获
![](https://i-blog.csdnimg.cn/blog_migrate/f6a503043d462c67791280d3ddd8670d.png)
解释:2.被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那一个:(同一个位置不可有两个相同的捕获,只能在不同位置有捕获)
![](https://i-blog.csdnimg.cn/blog_migrate/ba72ef6fb038a28d1d7d69df12bb0bc4.png)
假设输入cin >> len >> time; 是1,0,此处Func和main都有异常捕获,main调用Func函数,Func调用Division函数,Division中抛的异常,则会跳到最近的Func中被捕获,被捕获后面的代码正常运行,main中的捕获就不执行了。
double Division(int a, int b)
{
// 当b == 0时抛出异常
if (b == 0)
throw "Division by zero condition!";
else
return ((double)a / (double)b);
}
void Func()
{
try
{
int len, time;
cin >> len >> time;
cout << Division(len, time) << endl;
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
正常运行下面的代码:
int len, time;
cin >> len >> time;
cout << Division(len, time) << endl;
}
int main()
{
//Func();
try
{
Func();
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
catch (int errid)
{
cout << errid << endl;
}
return 0;
}
解释:4. catch(...)可以捕获任意类型的异常,只是不知道异常错误是什么。
try
{
}
catch (...) // 捕获没有匹配的任意类型异常
{
cout << "未知异常" << endl;
}
解释:5. 可以抛出的派生类对象, 使用基类捕获,这个在实际中非常实用,我们后面会详细讲解这个。
库中定义了一个基类叫 exception,抛异常的类型只要继承exception或者就是exception,即抛异常的类是exception的子类,就可以利用exception捕获。例如 bad_alloc类 是 基类exception 的子类,则new抛异常既可以用bad_alloc类捕获异常,也可以用基类exception捕获异常。
new抛异常 用bad_alloc类捕获
what()返回字符串 异常的信息——了解错误的描述
公司中标准的捕获写法:
try
{
……
}
catch(const exception& e) ——捕获正常的异常
{
……
}
catch(...) ——捕获某些新手写的未知异常
{
……
}
try
{
……
}
catch (const bit::Exception& e) 这里捕获自己定义的父类对象就可以
{
// 多态
cout << e.what() << endl;
}
catch (const std::exception& e) 这里捕获库中父类对象就可以
{
// 多态
cout << e.what() << endl;
}
catch (...) 这里捕获未知异常
{
cout << "Unkown Exception" << endl;
}
4.自定义异常体系
namespace bit
{
// 服务器开发中通常使用的异常继承体系
class Exception
{
public:
Exception(const string& errmsg, int id)
:_errmsg(errmsg)
, _id(id)
{}
virtual string what() const
{
return _errmsg;
}
int getid() const
{
return _id;
}
protected:
string _errmsg; // 描述错误信息
int _id; // 错误编码
// 堆栈信息
};
class SqlException : public Exception
{
public:
SqlException(const string& errmsg, int id, const string& sql)
:Exception(errmsg, id)
, _sql(sql)
{}
virtual string what() const
{
string str = "SqlException:";
str += _errmsg;
str += "->";
str += _sql;
return str;
}
private:
const string _sql;
};
class CacheException : public Exception
{
public:
CacheException(const string& errmsg, int id)
:Exception(errmsg, id)
{}
virtual string what() const
{
string str = "CacheException:";
str += _errmsg;
return str;
}
};
class HttpServerException : public Exception
{
public:
HttpServerException(const string& errmsg, int id, const string& type)
:Exception(errmsg, id)
, _type(type)
{}
virtual string what() const
{
string str = "HttpServerException:";
str += _type;
str += ":";
str += _errmsg;
return str;
}
private:
const string _type;
};
void SQLMgr()
{
if (rand() < RAND_MAX / 10)
{
throw SqlException("权限不足", 100, "select * from name = '张三'");
}
else
{
cout << "Sql success" << endl;
}
}
void CacheMgr()
{
if (rand() < RAND_MAX / 10)
{
throw CacheException("权限不足", 100);
}
else if (rand() < RAND_MAX / 4)
{
throw CacheException("数据不存在", 101);
}
else
{
cout << "Cache success" << endl;
}
SQLMgr();
}
void SeedMsg(const string& str)
{
if (rand() < RAND_MAX - 10000)
{
throw HttpServerException("SeedMsg::网络错误", 2, "put");
}
else if (rand() < RAND_MAX / 10)
{
throw HttpServerException("SeedMsg::你已经不是对方好友", 1, "post");
}
else
{
cout << "消息发送成功!->" << str << endl;
}
}
void HttpServer()
{
if (rand() < RAND_MAX / 10)
{
throw HttpServerException("请求资源不存在", 404, "get");
}
else if (rand() < RAND_MAX / 10)
{
throw HttpServerException("权限不足", 501, "post");
}
else
{
cout << "Http success" << endl;
}
CacheMgr();
}
}
int main()
{
srand(time(0));
while (1)
{
//this_thread::sleep_for(chrono::seconds(1));
::Sleep(1000);
try
{
//bit::HttpServer();
// 发送出现网络错误,要求重试10次
// 权限错误就直接报错 -- 17:20继续
for (size_t i = 0; i < 10; ++i)
{
try
{
bit::SeedMsg("你好啊!今晚一起看电影怎么样?");
break;
}
catch (const bit::Exception& e)
{
if (e.getid() == 2) // 异常编码的价值,针对某个错误进行特殊处理
{
cout << "网络错误,重试发消息第" <<i<<"次"<< endl;
continue;
}
else // 其他错误
{
//break;
throw e; // 异常重新抛出
}
}
}
}
catch (const bit::Exception& e) // 这里捕获父类对象就可以
{
// 多态
cout << e.what() << endl;
}
catch (const std::exception& e) // 这里捕获父类对象就可以
{
// 多态
cout << e.what() << endl;
}
catch (...)
{
cout << "Unkown Exception" << endl;
}
}
return 0;
}
4.异常规范
这里表示这个函数会抛出A/B/C/D中的某种类型的异常
void fun() throw(A,B,C,D);
这里表示这个函数只会抛出bad_alloc的异常
void* operator new (std::size_t size) throw (std::bad_alloc);
这里表示这个函数不会抛出异常
void* operator delete (std::size_t size, void* ptr) throw();
C++11 中新增的noexcept,表示不会抛异常
thread() noexcept;
thread (thread&& x) noexcept;
5.异常的优缺点
C++异常的优点:
![](https://i-blog.csdnimg.cn/blog_migrate/311c7f12006999b313a779755933ad71.png)
3. 很多的第三方库都包含异常,比如boost、gtest、gmock等等常用的库,那么我们使用它们
![](https://i-blog.csdnimg.cn/blog_migrate/5fa675cecf221b97d760907ef7ebbfae.png)
C++异常的缺点:
其他语法,异常机制基本差不多
C+ +独有缺陷:
1、标准库定义不够好用。还想看堆栈等都不支持等,所以很多公司自己定义一套自己的。
2、C+ +没有垃圾回收器,所以申请内存和释放内存位置要非常小心。容易泄漏,需要RAII机制再补充。