一、抛异常
为什么要抛异常? 我们日常使用的软件和游戏,都时不时会出现一些bug,可能是某个按钮打不开,可能是信息发不出去,这些都可能是“异常”。 那么作为一款已发布的应用程序,我们就需要保证,即便发生了异常,也不要终止整个程序,保证应用程序的健壮性。
try catch
一般我们会在可能会发生异常的代码区尝试抛异常,也就是try的区域,当发生(检测到)异常后,就会跳转到catch区域,catch区域是为了尝试解决异常,即便无法解决,也不让异常终止整个程序,并记录日志信息方便debug。
示例代码如下
#include<iostream>
#include<exception>
void Alloc_func()
{
void* ptr = new int[1000000000000000];
delete ptr;
}
int main()
{
try {
Alloc_func();
}
catch(std::exception& e){
std::cerr << "exception caught: " << e.what() << std::endl;
}
return 0;
}
该示例代码申请了过大的堆空间,抛出bad_alloc异常,如果不try catch,该代码则直接崩溃。
二、使用步骤
1.throw
是不是抛异常只能抛出std::exception类呢? 答案 不是的!
我们想抛什么类型就可以通过throw抛出去。
int divide(int i, int j)
{
if (j == 0)
throw "发生除零错误!";
return i / j;
}
int main()
{
try {
int a, b;
std::cin >> a >> b;
divide(a , b);
}
catch(const char* str){
std::cerr << "exception caught: " << str << std::endl;
}
return 0;
}
一旦throw后,则直接到catch区域。
那是不是只能有一个catch?
不是的,可以有多个catch区,当有多个catch时,会匹配对应类型的catch进行跳转。
int divide(int i, int j)
{
if (j == 0)
throw (void*)"发生除零错误!";
return i / j;
}
int main()
{
try {
int a, b;
std::cin >> a >> b;
divide(a , b);
}
catch (int& rv)
{
std::cerr << "exit code: " << rv << std::endl;
}
catch(const char* str){
std::cerr << "exception caught: " << str << std::endl;
}
catch (...) //可以接收所以抛出的类型
{
std::cerr << "unknown exception!" << std::endl;
}
return 0;
}
这里需要注意的是catch(…)可以接收所以抛出的类型。
那如果有多个catch对应类型符合,会匹配哪一个?
会匹配最近的那一个。
自我实现Expection
在一些大项目下,库提供的expeiction类并不能完全满足我们的需求,所以很多大公司都会自己写一套它们自己的Expection类,今天我们也来自己实现一下。
由于一般大项目需要分组进行,所以规定每个组最好是抛自己相关模块的那个异常,这里就可以使用到多态。
//Expection.hpp
#pragma once
#include<iostream>
#include<string>
class Exception {
public:
Exception(int errid, const std::string& msg)
:_errid(errid)
,_msg(msg){}
virtual std::string what() const
{
return _msg;
}
protected:
int _errid;
std::string _msg;
};
class loadException : public Exception
{
public:
loadException(int errid, const std::string& msg, const std::string& load)
:Exception(errid,msg)
,_load(load) {}
virtual std::string what() const
{
std::string str = "loadService: ";
str += _msg;
str += " -> ";
str += _load;
return str;
}
private:
std::string _load;
};
class encryptException : public Exception
{
public:
encryptException(int errid, const std::string& msg, const std::string& type)
:Exception(errid, msg)
, _type(type) {}
virtual std::string what() const
{
std::string str = "encryptService: ";
str += _msg;
str += " -> ";
str += _type;
return str;
}
private:
std::string _type;
};
class sendException : public Exception
{
public:
sendException(int errid, const std::string& msg)
:Exception(errid, msg)
{}
virtual std::string what() const
{
std::string str = "sendService: ";
str += _msg;
return str;
}
};
#include"Exception.hpp"
#include<time.h>
void sendService()
{
srand(time(nullptr));
if (rand() % 7 == 0) throw sendException(4, "sendService exception: Network connection timeout ");
std::cout << "Success !" << std::endl;
}
void encryptService()
{
srand(time(nullptr));
if (rand() % 9 == 0) throw encryptException(3, "encryptService exception","illegal character ");
if (rand() % 12 == 0) throw encryptException(3, "encryptService exception","encrypt error ");
sendService();
}
void loadService()
{
srand(time(nullptr));
if (rand() % 10 == 0) throw loadException(3, "loadService exception","load timeout ");
encryptService();
}
int main()
{
while (1)
{
try {
std::this_thread::sleep_for(std::chrono::seconds(1)); //休眠1s
loadService();
}
catch (const Exception& e) {
std::cout << "exception caught: " << e.what() << std::endl;
}
catch (...)
{
std::cout << "exception caught: unknown exception" << std::endl;
}
}
return 0;
}
异常的重新抛出
在有些场景下,有可能单个的catch不能完全处理一个异常,在进行一些校正处理以后,希望再交给更外层的调用链函数来处理,catch则可以通过重新抛出将异常传递给更上层的函数进行处理。
double Division(int a, int b)
{
// 当b == 0时抛出异常
if (b == 0)
{
throw "Division by zero condition!";
}
return (double)a / (double)b;
}
void Func()
{
int* array = new int[10];
try {
int len, time;
std::cin >> len >> time;
std::cout << Division(len, time) << std::endl;
}
catch (...)
{
std::cout << "delete []" << array << std::endl;
delete[] array;
throw; //这种写法用于重复抛出,捕捉到什么类型就抛什么类型
}
std::cout << "delete []" << array << std::endl;
delete[] array;
}
int main()
{
try
{
Func();
}
catch (const char* errmsg)
{
std::cout << errmsg << std::endl;
}
return 0;
}