C++学习笔记----异常处理(throw、try、catch)
文章目录
- 1.throw抛出异常
- 2.try catch捕获异常
- 3.noexcept关键字
- 4.标准异常和自定义异常
1.throw抛出异常
throw用于抛出异常,当函数抛出异常后该函数的运行将会终止,并将控制权转交给异常处理代码。
例子:
void ten(int *a,int size)
{
int n=10;
if(10>=size)
{
throw exception("数组越界");
}
else{
cout<<a[10]<<endl;
}
}
该程序会抛出异常,其异常类型为exception。
展开
当用throw语句抛出异常后,throw语句后面的语句将不会被执行,直到沿着调用链查找到异常处理块,否则将会导致程序的终止,在沿着调用链进行展开时,编译器将负责销毁在这个块中创建的对象,如果是类类型的对象,则会负责调用其析构函数。
析构和异常
析构函数总是会被执行的,但是函数函数中负责处理资源释放的代码可能被跳过。因此当我们在析构函数中抛出异常时,我们应该在析构函数内部对异常处理。否则可能导致资源没释放,对于资源的控制我们应该用类进行控制,且在析构函数中将其正确的释放。、
抛出局部对象
异常的处理时沿着调用链进行处理的,当退出某个块时,块内相应的资源会被释放,因此抛出指向局部对象的指针或引用将会是一种错误,同理函数返回局部对象的指针或者引用也将会是一种错误。因此抛出指针时应该保证指针指向的对象时存在的。
2.try catch捕获异常
我们用try…catch的方式进行捕获异常,把会发生异常代码或着调用放在try语句块内,在catch语句块内进行异常处理,其中catch的参数是我们要捕获的异常。
try{
ten(a,10);//该调用会产生越界异常
}catch(exception &e)
{
cout<<e.what()<<endl;
}catch(...)
{
throw;
}
catch子句中的参数和函数的传参很相似,穿的引用则会改变实际的对象,如果传入的是对象则实际上改变的是一个副本。对于异常的匹配,一般是按照顺序进行匹配的,所以在书写代码时越是专门的异常处理越是要放在catch列表的前端,如果catch中存在继承的关系,我们应该将继承链底端的异常处理放置在catch的前端。
重新抛出
一条catch语句使用throw将异常传递给另一个catch语句处理,这里的throw语句不包含任何的表达式,仅是一条简单的throw语句。空的throw语句只出现在catch语句或者catch直接或间接调用的函数中。
捕获所有异常的catch
catch(...){
}
上述语句可以捕获所有的异常,通常和重新抛出语句一起使用,catch执行完成一部分工作后将其他的处理转交给其他的处理函数,当catch(…)和其他处理语句一起使用时应当把catch(…)放在catch列表的最后。
构造函数和异常
当构造函数的初始化列表发生异常时,构造函数体内的异常还未准备,因此构造函数体内的异常捕捉无法捕捉函数初始化列表产生的异常,为了捕捉函数初始化列表的异常我们需要将函数写成函数ry语句块
如下:
template <typename T>
Blob<T>::Blob(std::initializer_list<T> il)try:data(std::make_shared<std::vector<T>(il))
{
}catch(const std::bad_alloc &e){handle_out_of_memory(e);}
处理构造函数初始值唯一的方法是将构造函数写成函数try语句块。
3.noexcept关键字
noexcept关键字有两个作用,一个用于指明函数是否会抛出异常,另一个作用则是用于判断函数是否抛出异常。
声名函数不会抛出异常
具体用法如下:
void test(int) noexcept; //该函数不会抛出异常
void test(int);//该函数可能抛出异常
如果一个函数使用了noexcept同时有抛出异常,那么编译器将会立即调用terminate将程序终止。
带有参数的noexcept
void test(int) noexcept(true); //该函数不会抛出异常
void test(int)(false);//该函数可能抛出异常
noexcept运算符
将会返回一个bool值,如果函数返回true则表示函数不会抛出异常,否则返货false。
noexcept(test(i));//返回true表示test(i)不会抛出异常,否则返回false;
void f() noexcept(noexcept(g()));//f和g的异常说明一致
4.标准异常和自定义异常
c++标准库定义了一些标准异常,这些异常分别定义在4个头文件中:
- exception头文件定义了最通用的异常类exception,进报告异常的发生但不提供信息。
- stdexcept头文件定义了常用的异常,如下表:
- new头文件定义了bad_alloc异常类。 - type_info定义了bad_cast异常类。
所有的标准异常都是继承自exception的,便准已成的继承体系如下:
除了使用标准异常我们还可以使用自定义的异常,自定义异常通常继承自标准异常,其用法和捕捉方式和标准异常没有太大区别。
爱吃萝卜的大白熊: 可以实现
2301_79872098: 为什么输入不了"+P呀
激情澎湃的gan: 发生这种问题的原因是设置断点的函数名在源码中没有定义,说明要么是gdb写错函数名,要么源码写错函数名
weixin_59062515: 初学者冒昧问一下,那个黑白棋子是如何打印出来的?
小军要学习: 佬