第三章,异常

条款14 明智运用exception specifications

不一致性问题

如果函数抛出并未列入其exceptions specifications的exception,特殊函数unexpected会被调用,这个函数的默认行为是调用terminate,而terminate默认行为是调用abort;因此,一旦函数抛出异常违反了exception specifictions,默认结果是程序被中止。局部变量不会获得销毁的机会,因为abort会让程序停摆,没有机会执行此类的清理工作。

extern void f1(); //可以抛出任何类型异常

void f2() throw(int)
{
...
f1(); //编译器允许这样写,即使抛出非int类型异常;但明显产生不一致性,很可能会导致前述问题的发生
...
}

如何解决不一致性的问题?
(1)避免将exception specifications放在“需要类型自变量”的template身上

template<class T>
bool operator==(const T& lhs, const T& rhs) throw() //声明该函数不会抛出任何异常
{
return &lhs == &rhs;//但是如果&操作符被重载,仍然会有抛出异常的可能,违反throw()不抛出异常的规定,走上exception之路
}

是的,避免不一致性问题的第一个方法就是对于exception specifications是否适用的情况多加判别

(2)违反异常规范触发的unexcepted函数会先于catch语句块执行,有必要使用std::set_unexcepted替换默认的unexcepted函数

总结

异常规范exception specifications是一把双刃剑,一方面对函数希望抛出什么样的exception提供了卓越的说明,但是在违反异常规范调用默认的unexcepted函数会带来一些麻烦。在将其加入程序函数之前,请考虑它所带来的程序行为是否是开发者想要的。

注意

C++98与C++03完全支持异常规范; C++11废弃了throw(Type),保留throw(),等价于noexcept; C++17 移除throw(Type),保留throw(); C++20+仅兼容throw(),推荐noexcept