引导
throw()
在C++11前,使用throw(optional_type_list)
来声明某些函数,表示该函数不会抛出异常。
如果函数抛出了异常,则调用 unexpected()
函数(C++98 标准规定,函数出现异常但未被捕获时会调用 unexpected()
函数(该过程包含运行时检查异常类型是否存在于optional_type_list中,不在的话将直接terminate),该函数默认实现是调用 terminate()
函数使得程序终止)。如果 unexpected()
函数直接调用 terminate()
函数,则程序直接退出,否则跳转到处理异常的 catch()
语句继续处理异常。
class X
{
public:
void fx()throw() {
};
};
由此可见,throw()的过程还是有一些麻烦,其实对于一些程序员来讲,很多数时候只关心当前函数是否会抛出异常,而不是抛出什么样类型的异常。
移动语义与throw()
另外C++11中引入了移动语义,比如我们进行容器数据拷贝时,使用移动语义是一种节省资源(窃取)的做法。但是移动语义本身就包含一个异常缺陷:
我们在进行容器间的数据搬移的过程中,由于内存或者其他原因发生了异常,搬运中止。将会导致原容器和目标容器都将无法正常使用,一部分数据已经被搬走,此时也没法恢复(无法保证恢复过程中不抛出异常)。
为什么会将这两者扯在一起呢? 那是因为throw()
并不能根据容器中移动的元素是否会抛出异常来确定移动构造函数是否允许抛出异常,但是下面讲到的noexcept()
作为运算符时可以做到。
C++11 noexcept
noexcept既是一个说明符,也是一个运算符。
作为异常说明符:
- 告诉接口调用者,该函数运行过程中不会抛出异常,接口使用者不必为该接口写一些异常处理代码;
- 编译器也知道该函数不会抛出异常,可以让编译器更放心的做一些优化;
- 不是说函数就不会抛出异常,如果函数抛出异常,将直接调用
terminate()
函数结束进程,该符号只是一种指示符号,不是承诺。
class X
{
public:
void fx()noexcept {
}
int GetValue()const noexcept {
return v; }
private:
int v = 100;
};
作为运算符: