异常何时会迷失方向
异常被引发之后,有两种情况会导致问题:
意外异常(unexpected exception):
如果异常是在带异常规范的函数中引发的,则必须与规范列表中的某种异常匹配(在继承层次结构中,类类型与这个类机器派生类的对象匹配)就是得有个catch块能跟你写的异常符合/能接受你那异常,否则则成为意外异常.(C++11已经摒弃这东西了,然而有的代码还在用它)
举个正确的栗子:
通过给函数制定异常规范,可以让函数的用户知道要捕获那些异常.放屁,真水
未捕获异常(uncaught exception):
如果异常不是在函数中引发,则必须捕获他.如果没有捕获(在没有try块或没有catch块时,将出现)
在默认情况下,出现上述情况程序将被终止,然而可以修改程序对上述异常的反应…
未捕获异常不会导致程序立刻停止,首先会调用terminate()函数,terminate()会调用abort()函数,但可以修改terminate()调用的函数(不让他调用abort()).可以使用set_terminate()函数来修改.(在#include
typedef使得terminate_handler成为一个指向没有参数和返回值的函数的指针.set_terminate()将这个不带任何参数且返回类型为void的函数的名字(地址)作为参数,并且返回这个函数的地址,如果set_terminate()被多次调用,则terminate()将调用最后一次set_terminate调用设置的函数.
举个栗子:一个未被捕获的异常导致程序打印一条消息,然后调用exit()函数.
现在如果程序引发未捕获异常,则将调用terminate(),而terminate()将会调用myQuit().
原则上,异常规范应该包含函数调用的其他函数所引发的异常.比如A()调用了B(),而B()可能引发retor对象异常,则A(),B()的异常规范中都应该包含retort.
如果函数引发了其异常规范中没有的异常呢?这样处理起来就比较繁琐,所以C++11也将其摒弃.所以说这玩意咋看都像是坑
那么在这种情况下,行为与未捕获异常极其相似,程序将调用unexpected().这函数将调用terminate(),后者在默认情况下调用Abort().跟terminate()一样,有一个可以修改其行为的set_terminate()一样,也有一个用于修改unexpected()的set_unexpected():
然而set_unexpected()比set_terminate()更加严格,unexpected_handler函数可以:
- 通过调用terminate()(默认行为).abort(),exit()等来终止程序
- 引发异常
- 如果新引发的异常原来的相匹配,则程序将开始寻找引发新异常的函数规范;
- 如果新引发的异常跟原来的不一样,且异常规范中没包括
sed::bad_exception
则将调用terminate(). - 如果新引发的异常跟原来的不一样,且异常规范中包括了
sed::bad_exception
则不匹配的异常会被sed::bad_exception
异常取代.
有关异常的注意事项
- 使用异常会降低程序运行速度.(
废话 - 异常规范不适用于模板. 因为模板函数引发的异常随特定的具体化而异.
- 异常和动态内存分配并非总能协同工作
动态内存分配和异常:
正常:
当函数结束时,将为mesg调用string的析构函数,虽然throw过早的终止了函数,但因为栈解退的存在使得析构函数仍然被调用完成清理.
有瑕疵:
这里有个瑕疵: 当栈解退时,将删除栈中的变量mesg,但函数过早的终止意味着句尾的delete [] mesg;
被忽略.指针虽然没了,但内存还没被释放且不可访问…这就容易造成一些问题..
修改版:
然而可以用智能指针解决该问题