C++中的异常主要由三个关键字构成:try
,catch
,throw
。
其中throw
抛出异常,try
包围可能发生异常的语句,catch
用来做异常处理。
看一个例子:
#include <iostream>
#include <string>
using namespace std;
int main()
{
try {
throw(string("gaoyuelong"));
}
catch (string str) {
cout << str << endl;
}
return 0;
}
throw
可以抛出任意异常,只要catch进行相应的捕获即可。
比如:
int main() {
int age = 100;
try {
if (age > 90) {
throw(age);
//throw后面的语句不会被执行到
cout << "123" << endl;
}
}
catch (int age) {
cout << age << " is too big" << endl;
}
return 0;
}
上面的例子中提到throw
后面的语句不会被执行值得注意。
异常会向外传播,直到有相应的catch
捕获异常,比如:
void inner()
{
//在外层被捕获
throw("123");
}
void outer()
{
try
{
inner();
}
catch (...)
{
cout << "exception caught" << endl;
}
}
int main()
{
outer();
return 0;
}
如果一直向外传播都没有找到匹配的catch
捕获,程序会崩溃。catch(...)
表示捕获任意类型的异常。
如果我们想在抛出异常时,携带一些信息,帮助开发人员更好的调用调试,可以继承自exception
类,重写what
方法:
class idontknowwhatshappening : public exception
{
public:
idontknowwhatshappening() = default;
~idontknowwhatshappening() = default;
idontknowwhatshappening& operator=(const idontknowwhatshappening&) = default;
//返回const char*而不是string,string可能也会发生异常
const char* what() { return "I don't know what's happening"; };
};
void inner()
{
try
{
throw(idontknowwhatshappening());
}
catch (idontknowwhatshappening &e)
{
cout << e.what() << endl;
}
}
void outer()
{
try
{
inner();
}
catch (...)
{
cout << "exception caught" << endl;
}
}
异常被捕获时,会按照catch定义的语句顺序,挨个进行匹配,执行第一个匹配完成的流程:
class idontknowwhatshappening : public exception
{
public:
idontknowwhatshappening() = default;
~idontknowwhatshappening() = default;
idontknowwhatshappening& operator=(const idontknowwhatshappening&) = default;
const char* what() const { return "I don't know what's happening"; };
};
void inner()
{
try
{
throw(idontknowwhatshappening());
}
catch (const idontknowwhatshappening &e)
{
//匹配到则先执行这里
cout << e.what() << endl;
}
catch (exception &e)
{
cout << "e" << endl;
}
//而如果父类exception先进行捕获的话,就先执行父类的捕获
//catch按顺序执行,他会执行第一个能匹配到的捕获
/*catch (exception &e)
{
cout << "e" << endl;
}
catch (const idontknowwhatshappening &e)
{
cout << e.what() << endl;
}*/
}
如果异常在被第一个catch
捕获时,需要修改对象的值,这时需要引用对象:
class i : public exception
{
public:
i() = default;
~i() = default;
i& operator=(const i&) = default;
const char* what() { return "exception i"; }
string s;
};
void outer()
{
try
{
throw i();
}
catch (i& I)//这里使用引用
{
I.s = "123";
cout << "exception caught" << endl;
cout << I.s << endl;
}
}
若当前catch
发现处理不了异常,需要继续向上传递时,使用throw
:
void outer()
{
try
{
throw i();
}
catch (i& I)
{
I.s = "123";
cout << "exception caught" << endl;
cout << I.s << endl;
//继续向上层抛出
throw;
}
}
int main() {
try
{
outer();
}
catch (i &I)
{
cout << "main: " << I.s << endl;
}
return 0;
}
如果一个函数我们确保他不会发生异常,可以使用noexcept
关键字,这样编译器可能会对这个函数做一些不会抛出异常的优化
//用noexcept修饰后,不能再抛出异常了,否则程序会崩溃
const char* foo() noexcept
{
throw("123");
}
int main()
{
try
{
foo();
}
catch (...)
{
cout << "exception caught" << endl;
}
return 0;
}
关于异常的编码规范,一般关于异常的处理都放在外面做,而函数自身,只需要进行检查,若不符合规范抛出异常让外层处理。比如:
void Process(int n)
{
if (n > 3)
{
//去外面处理,不要在使用方处理
throw runtime_error("number too big");
}
}
int main()
{
vector<int> v = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++)
{
try {
Process(v[i]);
cout << v[i] << endl;
}
catch(runtime_error &e)
{
cout << e.what() << endl;
}
}
return 0;
}
以上,便是对C++中异常的一些基础使用,希望对你有用。
如果你觉得文章还不错,欢迎点赞评论哦!关注账号,你还会收到关于C++的更多知识哦!!