目录
1.C语言传统的处理错误的方式
2.C++异常概念
int main()
{
try
{
//要捕获异常的区域
}
catch (const Exception& e1)
{
// catch()块
}
catch (const Exception& e2)
{
// catch()块
}
catch (const Exception& e3)
{
// catch()块
}
// ...
return 0;
}
3.异常的用法
3.1. 异常的抛出和捕获
double Division(double left, double right)
{
if (right == 0)
{
// 当right为0时,会抛出异常
throw "this is a error except 0";
}
else
{
return left / right;
}
}
void Func1(void)
{
double x, y;
std::cin >> x >> y;
std::cout << Division(x, y) << std::endl;
}
int main()
{
while (1)
{
try
{
Func1();
}
catch (const char *error_str)
{
std::cout << error_str << std::endl;
}
}
return 0;
}
double Division(double left, double right)
{
if (right == 0)
throw "this is a error except 0";
else
return left / right;
}
void Func1(void)
{
double x, y;
std::cin >> x >> y;
try
{
std::cout << Division(x, y) << std::endl;
}
catch (const char* error_msg)
{
std::cout << error_msg << std::endl;
}
}
int main()
{
while (1)
{
try
{
Func1();
}
catch (const char *error_str)
{
std::cout << error_str << std::endl;
}
}
return 0;
}
// 由于异常可以随便抛,如果不规范抛异常,那么很有可能出现
// 无法匹配的异常,因此这里的catch为了防止出现这种问题(可以捕获任意类型的异常)
// 一般情况这个catch语句放在最后,防止一些异常没有被捕获,进程crash
// 增强代码的健壮性
catch (...)
{
std::cout << "Unknown error" << std::endl;
}
namespace Xq
{
class exception
{
public:
exception(const std::string& error_msg, int error_id)
:_error_msg(error_msg)
, _error_id(error_id)
{}
const std::string& get_msg() const
{
return _error_msg;
}
const int get_id() const
{
return _error_id;
}
private:
std::string _error_msg;
int _error_id;
};
double Division(double left, double right)
{
if (right == 0)
{
throw(exception("this a error of except 0", 1));
}
else
return left / right;
}
void Func1(void)
{
double x, y;
std::cin >> x >> y;
std::cout << Division(x, y) << std::endl;
}
}
int main()
{
while (1)
{
try
{
Xq::Func1();
}
catch (const Xq::exception& e)
{
std::cout << "error code:> " << e.get_id() << std::endl;
std::cout << "error msg:> " << e.get_msg() << std::endl;
}
catch (...)
{
std::cout << "Unknown error" << std::endl;
}
}
return 0;
}
3.2. 异常的重新抛出
double Division(double left, double right)
{
if (right == 0)
throw "this is a error except 0";
else
return left / right;
}
void Func1(void)
{
int* arr = new int[10];
double x, y;
std::cin >> x >> y;
std::cout << Division(x, y) << std::endl;
std::cout << "delete[] " << arr << std::endl;
delete[] arr;
}
int main()
{
while (1)
{
try
{
Func1();
}
catch (const char *error_str)
{
std::cout << error_str << std::endl;
}
catch (...)
{
std::cout << "Unknown error" << std::endl;
}
}
return 0;
}
void Func1(void)
{
int* arr = new int[10];
double x, y;
std::cin >> x >> y;
try
{
std::cout << Division(x, y) << std::endl;
}
catch (const char* str)
{
std::cout << "delete[] " << arr << std::endl;
delete[] arr;
// 重新抛出异常
// 可以只使用 throw; 重新抛出当前异常
//throw;
// 或者使用 throw str; 重新抛出复制的异常对象
throw str;
}
std::cout << "delete[] " << arr << std::endl;
delete[] arr;
}
double Division(double left, double right)
{
if (right == 0)
throw "this is a error except 0";
// 假设此时分母为1,也抛异常
else if (right == 1)
throw 1;
else
return left / right;
}
void Func1(void)
{
int* arr = new int[10];
double x, y;
std::cin >> x >> y;
try
{
std::cout << Division(x, y) << std::endl;
}
catch (const char* str)
{
std::cout << "delete[] " << arr << std::endl;
delete[] arr;
// 重新抛出异常
throw;
}
// 捕获未匹配的异常类型
catch (...)
{
std::cout << "delete[] " << arr << std::endl;
delete[] arr;
// 重新抛出异常
throw;
}
std::cout << "delete[] " << arr << std::endl;
delete[] arr;
}
3.3. 异常安全
3.4. 异常规范
// C++98:
// 注意: 这里的异常声明并不是必须的,比较繁琐,
// 实际中很多人没有去遵守规范,形同虚设
// 表示这个函数不会抛异常
void func1() throw();
// 表示这个函数可能会抛出type1或type2或type3的异常
void func2() throw(type1, type2, type3);
// 这里表示这个函数只会抛出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
void func3() noexcept;
// 如果一个函数可能会抛异常,什么都不加
void func4();
// 在这里经测试发现, 如果一个函数被noexcept声明了,但实际上却抛异常了
// 编译器会报警告,但没有报错
// 而如果此时捕获异常就会导致进程崩溃
4. 自定义异常体系
namespace Xq
{
class exception
{
public:
exception(const std::string& error_msg, int error_id)
:_error_msg(error_msg)
, _error_id(error_id)
{}
// 在这里为了构成多态
virtual const std::string what() const
{
return _error_msg;
}
const int get_id() const
{
return _error_id;
}
protected:
const std::string _error_msg;
int _error_id;
};
class sql_exception : public exception
{
public:
sql_exception(const std::string& error_msg, int error_id, const std::string sql)
:exception(error_msg, error_id)
, _sql(sql)
{}
virtual const std::string what() const
{
std::string ret = "sql_exception:";
ret += _error_msg;
ret += ": ";
ret += _sql;
return ret;
}
private:
const std::string _sql;
};
class cache_exception : public exception
{
public:
cache_exception(const std::string& error_msg, int error_id)
:exception(error_msg, error_id)
{}
virtual const std::string what() const
{
std::string ret = "cache_exception: ";
ret += _error_msg;
return ret;
}
};
class http_exception : public exception
{
public:
http_exception(const std::string& error_msg, int error_id, const std::string& type)
:exception(error_msg, error_id)
, _type(type)
{}
virtual const std::string what() const
{
std::string ret = "http_exception: ";
ret += _error_msg;
ret += ": ";
ret += _type;
return ret;
}
private:
const std::string _type;
};
void sql_mgr(void)
{
if (rand() % 2 == 0)
{
// 抛子类对象,父类对象去捕捉,构成多态
throw sql_exception("没有权限", 5, "select * from name = 李四");
}
}
void cache_mgr(void)
{
if (rand() % 3 == 0)
{
// 抛子类对象,父类对象去捕捉,构成多态
throw cache_exception("没有权限", 10);
}
else if (rand() % 4 == 0)
{
// 抛子类对象,父类对象去捕捉,构成多态
throw cache_exception("没有该数据", 11);
}
sql_mgr();
}
void http_serve(void)
{
if (rand() % 5 == 0)
{
// 抛子类对象,父类对象去捕捉,构成多态
throw http_exception("请求资源不存在", 20, "pos");
}
cache_mgr();
}
}
int main()
{
srand((unsigned int)time(nullptr));
while (1)
{
try
{
Sleep(1000);
Xq::http_serve();
}
catch (const Xq::exception& e)
{
std::cout << e.what() << std::endl;
}
catch (...)
{
std::cout << "Unknown error" << std::endl;
}
}
return 0;
}
5.标准库异常体系