异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的 直接或间接的调用者处理这个错误。
throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
catch: 在您想要处理问题的地方,通过异常处理程序捕获异常.catch 关键字用于捕获异 常,可以有多个catch进行捕获。
try: try 块中的代码标识将被激活的特定异常,它后面通常跟着一个或多个 catch 块。
如果有一个块抛出一个异常,捕获异常的方法会使用 try 和 catch 关键字。
void func1() { int x, y; cin >> x >> y; if (y == 0) { throw "abc"; } cout << x / y; } int main() { try { func1(); } catch (const char* c) { cout << c<<endl; } }
这是一个普通的捕获异常的代码
一般发生除0错误时,程序会直接报错,终止程序
而为了不让程序直接终止,我们用异常捕获
throw:抛异常,可以抛任意类型的异常,抛出去时,会优先抛给进的函数,知道能捕获到它的异常为止,若都没有,则报错。
void func1() { int x, y; cin >> x >> y; if (y == 0) { throw "abc"; } cout << x / y; } void func2() { try { func1(); } catch (const char* c) { cout << c; } } int main() { try { func1(); } catch (const char* c) { cout << c<<endl; }
catch(...)
{
cout<<"异常错误";
} return 0; }
这段代码 func2也try保护了func1 所以func1的异常,会优先被func2捕获。而不是被main捕获
catch(...)//这段代码是为了捕获没定义捕获的代码 也是能捕获任意类型的代码。但无法知道捕获过来的到底是哪里的异常。
- 1.在抛出异常对象后,会生成异常对象的拷贝,因为抛出的异常对象,可能是临时对象,所以会生成一个拷贝对象,这个拷贝临时对象在被catch(捕获)后会销毁。
- 2.可以抛出派生类对象,使用基类捕获,这个在实际非常实用
在函数调用链中异常栈展开匹配原则
- 1.检查throw本身是否在try内,如果是,再召匹配的catch,若没有,则调用到catch的地方处理
- 2.没有匹配的catch则退出当前函数栈,继续在调用函数栈中召匹配的catch
- 3.如果到main函数找,依旧没有匹配,则终止程序,所以都需要再最后加上 catch(...) 捕获未知的异常
- 4.找到匹配catch句子后,会直接catch内的所有句子。
异常编码的价值,针对某种错误进行特殊处理。
class A { public: A(){} }; void foo() { throw new A; }
这条代码 正常捕获 为:catch (A * x)
因为 异常是按照类型来捕获的,throw后抛出的是A*类型的异常,因此要按照指针方式进行捕获
异常安全问题
int func3(int x, int y) { if (y == 0) throw "abc"; return x / y; } int main() { srand(time(0)); //func2(); while (1) { try { //func1(); int* p = new int[1024*10]; p[0] = rand(); p[1] = rand() % 5; cout << func3(p[0], p[1])<<endl; delete p; } catch (const char* c) { cout << c<<endl; } } return 0; }
这串代码的大致思路为,创建一个空间 然后在0和1放入随机值。放入func3函数内 如果y为0 会发生除0错误 然后捕获异常
那么原本的思路是 没发生异常 创建->计算->释放 发生异常时 创建->计算->发生异常捕获->释放
但是我们来看下它在任务管理器下发生的变化。
这里我们发现,内存是不断增长的。
这里可能有人会说,你开辟了空间肯定会涨啊,而且还是死循环。
记住,我确实是开辟了空间,但每次循环里我开辟好空间,计算后,都立刻释放空间。所以正常情况下,我们的内存是增长,然后释放,不断循环。是不会发生一直增长,而不释放的问题的。这就是内存泄漏问题。也就是本次的异常安全问题。
那么接下里。我来演示,正常情况,没有内存泄漏的问题。
可以看到,此次是正常情况下,内存是一直保持在9.7MB
那为啥会发生内存泄漏问题呢?
原因是 当发生了异常捕获时,那么我们的代码程序是会被throw直接抛出的,然后被catch捕获。那么本该执行delete代码,直接被跳过了,导致内存没有释放。再加上不断的循环,导致越来越多的内存没有释放,最终导致了内存泄漏问题。
也就是说 创建内存后 中间发生了异常,被抛出,程序直接走到了捕获异常那,而不是按照正常的代码逻辑走。 导致了最后没走到delete这段代码,没有成功释放。