在c++11标准之前,c++在函数声明中有exception specification(异常声明)的功能,用来指定函数可能抛出的异常类型。
voidFunc0() throw(runtime_error); voidFunc1() throw(); voidFunc2();
函数Func0可能抛出runtime_error类型的异常;函数Func1不会抛出任何异常;函数Func2没有异常说明,则该函数可以抛出任何类型的异常。
如果函数抛出了没有在异常说明中列出的异常,则编译器会调用标准库函数unexpected。默认情况下,unexpected函数会调用terminate函数终止程序。
这种异常声明的功能很少使用,因此在c++11中被弃用。c++11引入noexcept,具体用法如下。
voidFunc3() noexcept;
noexcept的功能相当于上面的throw(),表示函数不会抛出异常。如果noexcept修饰的函数抛出了异常,编译器可以选择直接调用std::terminate()终止程序运行。noexcept比throw()效率高一些。
voidFunc4() noexcept(常量表达式);
如果常量表达式的结果为true,表示该函数不会抛出异常,反之则有可能抛出异常。不带常量表达式的noexcept相当于noexcept(true)。
上面noexcept的用法是其作为修饰符时的用法,实际上noexcept还可以作为操作符,常用于模板中。
template <typename T> voidfunc5() noexcept( noexcept(T()) ) {}
第2个noexcept就是一个操作符,如果其参数是一个有可能抛出异常的表达式,则返回值为false(func5为noexcept(false),有可能会抛出异常),否则返回值为true(func5为noexcept(true),不会抛出异常)。
这样函数是否会抛出异常,可以由表达式进行推导,使得c++11更好的支持泛型编程。
noexcept被大量的使用在c++11的标准库中,用于提高标准库的性能,以及满足一些阻止异常扩散的需求。随便在c++11标准文档中搜索一下noexcept关键字,就知道它的应用有多广泛了。
c++11默认将delete设置成noexcept,这样可以提高应用程序的安全性,因为在析构函数中不应该抛出异常,而析构函数中经常会调用delete。
voidoperator delete(void* ptr) noexcept; voidoperator delete(void* ptr, const std::nothrow_t&) noexcept; voidoperator delete[](void* ptr) noexcept; voidoperator delete[](void* ptr, const std::nothrow_t&) noexcept; voidoperator delete(void* ptr, void*) noexcept; voidoperator delete[](void* ptr, void*) noexcept;
同样出于安全因素考虑,c++11将类的析构函数默认为noexcept(true)。但如果程序员显示的为析构函数指定noexcept(false),或者类的基类或成员有noexcept(false)的析构函数,则析构函数不会再保持默认值。
学习资料: 《深入理解c++11》《c++ primer》